Chapter I 简介
为什么要写爬虫?
- 每个网站都应该提供 API,但这是不可能的
- 即使提供了 API,往往也会限速,不如自己找接口
注意已知条件(robots.txt 和 sitemap.xml)
- robots.txt 可能会有陷阱
- sitemap 可能提供重要链接
估算网站的大小
一个简便方法是使用 site:example.com 但是,这种方法不适用于战争
识别网站使用的技术
-
builtwith 模块 pip install builtwith builtwith.parse(url) # returns a dict
-
python-whois 模块 pip install python-whois import whois whois.whois(url)
下载器
下载器需要提供几个功能:
- 错误重试,仅当返回的错误为500的时候重试,一般400错误可认为不可恢复的网页
- 伪装 UA
- 策略 a. 爬网站地图 sitemap b. 通过 ID 遍历爬取 i. ID 可能不是连续的,比如删除了记录 ii. ID 访问失效 n 以后可以认为遍历完全了。
- 可以利用相对连接转换 lxml 的 make_link_absolute 函数
- 处理 robots.txt 可使用标准库 robotsparser 模块 import robotsparser rp = robotparser.RobotFileParser rp.set_url('path_to_robots.txt') rp.read() rp.can_fetch("UA", "url") True or False
- 支持代理
- 下载限速,粒度要精确到每个站点。
- 避免爬虫陷阱,尤其是最后一页自身引用自身的例子 a. 记录链接深度
例子:https://bitbucket.org/wswp/code/src/chpter01/link_crawler3.py
Chapter II 数据抓取
抽取资源的方法
- 正则 不适合匹配网页结构,因为网页结构中的空白无关紧要,可能会破坏正则 Structural-based 适用于符合某种模式的数据本身,例如 IP 地址,如日期等 Content-based
- xpath 与 CSS 适用于匹配网页的结构信息 Strctual-based,lxml 的 CSS 选择器内部转换为 xpath 实现的,css 远不如 xpath 灵活
- BeautifulSoup, 慢,在生产代码中从未见过
下载的第二步是将获得的网页传递给 Extractor 提取内容可以通过传输到下载函数回调来处理,但这种耦合太强了
Chapter III 下载缓存
书中的缓存缓存了所有相应的缓存,包括500的错误响应。事实上,这种直接的不缓存是好的。 书中磁盘缓存把 url normalize 这里也加入了逻辑,感觉很混乱 请注意,使用磁盘文件缓存将受到磁盘单目录文件数量的限制,即使是 ext4 文件系统也不大
Chapter IV 并发下载
估计下载时间也很重要。每个链接下载需要多长时间,整个过程需要多长时间? 多线程下载例,手动模拟线程池
def process_queue(q): pass threads = [] while thread or crawl_queue: for thread in threads: if not threads.is_alive(): threads.remove(thread) while len(threads) < max_threads and crawl_queue: thread = threading.Thread(target=process_queue, daemon=True) thread.start() threads.append(thread) time.sleep(some_time)
性能的增长与线程和进程的数量并不是成线性比例的,而是对数比例,因为切换要花费一定的时间,再者最终是受限于带宽的
Chapter V 动态内容
逆向接口
依赖于 Ajax 网站看起来更复杂,但实际上数据和性能层的分离会更简单,但如果逆向工程不容易得到一般的方法,如何构建辅助工具? 表示网页上动态加载的地方,列出 js 列出可能的全局变量 jsonp 请求
利用 Ajax 在接口时,可以使用各种边界条件,如空置搜索条件和 *,置为 .
渲染动态网页
使用Qt 使用 Selenium 或者 PhantomJS,这时附加 Cookie 都是很严重的问题
Chapter VI 表单交互
隐藏的参数通常存在于登录表中,例如 form_key 也可能需要避免重复提交表单 cookie 验证
Wow,可直接从浏览器加载 Cookie,使用 browsercookie 模块
Chapter VII 验证码处理
使用机器识别验证码 使用 Pillow 和 pytesseract 但是 tessact 不是用来识别验证码的
锐化方法
img.convert('L') img.point(lambda x: 0 if x < 1 else 255, 'l') tessact.image_to_string(img)
还可以通过限定字符集提高识别率
也可以使用人工打码平台