爬虫tips

链接抓取

  • 根据首页链接抓取内容
  • 页面包含的链接放入一个set,避免重复
  • 解析robot.txt,避免下载禁止爬取的页面
  • 已经抓取过的链接放在一个set
  • 抽取深度达到限定值后停止,避免爬虫陷阱
  • 同一域名的两次下载之间设置延迟,避免爬取过快
  • 下载失败时重试下载(设置一个try_times参数,递归调用

得到一堆html页面

数据抓取

方法 性能 使用难度 安装难度
正则 困难 简单
Beautiful Soup 简单 简单
Lxml 简单 相对困难
如果爬虫的瓶颈在下载页面,不是数据抓取,那么可以使用BS
如果要抓的数据不多,使用正则更加高效率
lxml是最佳选择

正则

如果要选取的东西,格式很常见,有很多相似项,可以尝试指明它的父元素或者祖先元素,最好是有id属性 (:_< id是唯一的吧)

CSS选择器

  • 选择所有标签: *.
  • 选择a标签: a
  • 选择class=”link”的元素: .link
  • 选择class=”link”的a标签: a.link
  • 选择id=”home”的a标签: a#home
  • 选择父元素为a标签的所有span标签: a > span
  • 选择a标签内的所有span标签: a span
  • 选择title属性为”home”的所有a标签: a[title=home]

给链接抽取添加数据处理回调

  • 构造回调函数或者回调(定义**_call_()**方法)
  • 数据写入文件

下载缓存

磁盘缓存

  • 下载前检查缓存

  • 没有时再请求网页下载,并存至缓存

  • 设计URL到文件名的映射 : 注意命名格式限制,例如长度,允许的字符

  • 数据(html)可以压缩: zlib.compress|zlib.decompress

  • 保存时间戳,过期缓存失效

    缺点: 受限于文件系统,数量有限

数据库缓存

存储大量数据,没有复杂的连接操作,选择易拓展的NoSql
加载时间比文件系统多,但免于文件系统的限制

并发下载

多线程爬虫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#处理url的函数
def thread_crawler:
...
def process_url:
pass
...

#逻辑:设定一个线程池,最大线程数为max_threads.当有URL爬取时,检测是否有线程,有的话处理掉完成的线程, 再判断是否创建新线程
threads=[]
while threads or crawl_queue:
for thread in threads:
if not thread.is_allive():
#remove
threads.remove(thread)
#在多个线程中启动process_url,条件是当前线程数小于设定值,并且待爬队列不为空
while len(threads)<max_threads and crawl_queue:
thread = threading.Thread(target=process_url)
thread.start()
threads.append(thread)

多进程爬虫

有几个cpu创建几个进程

1
2
3
4
5
processes=[]
for i in range(num_cpus):
p=multiprocessing.Process(target=thread_crawler)
p.start()
processes.append(p)

动态内容

todo…