Google 图片爬虫

这里的 Google 图片爬虫指的是爬取在 Google 上通过关键词搜索得到的图片,由于最近需要一些特定领域的图片,而且现有的数据库满足不了要求,因此就想通过 Google 搜索筛选出这些特定领域的图片,然后下载下来后再进行人工筛选。这里采用了两种方法,区别在于是否需要解析网页端的 JS 代码。该项目的代码已经放到了 Github 上,详细代码参见这里

整体的思路就是先获取 Google 搜索结果页面的 html 代码,然后从中提取出图片的真实 URL,因为实际上 Google 也是通过爬虫来爬取这些图片的地址以及根据描述归类,所以图片并不存储在 Google 的服务器中。

这个过程中的一个关键点就是通过关键词 search_query 搜索得到的页面可直接通过下面这个 url 访问

https://www.google.com/search?q=search_query&source=lnms&tbm=isch

search_query 换成需要搜索的关键词即可。

这样便可以直接获取这个页面的源码,然后通过正则表达式解析出所有的图片的链接,这个方法只需要 python 的 urllib 库即可,对应的源码文件为 download_with_urllib.py

上面是第一种方法,这种方法比较简单,当时有一个问题就是每个关键词最多只能下载 100 张图片,原因是 访问上面的链接返回的 HTTP Response 中限制了最多只有前100张图片的URL,如果需要显示更多,则需要在解析页面中相应的 JS 代码,这就是接下来要介绍的第二种方法。

所谓解析 JS 代码,其实就是浏览器的滚动条向下滚动时,浏览器引擎解析了页面的 JS 代码,从而向 Google 的服务器发出新的请求,从而返回更多的图片,当向下滚动时到底时,会出现一个显示为 Show more results需要点击的按钮,只有点击后才能加载更多的图片,这些操作要通过浏览器完成,而 python 提供了一个 selenium 库,这个库通过相应的浏览器驱动来启动浏览器(不同的浏览器对应于不同的驱动),并在代码中制定具体的浏览器操作。

这里采用的是 FireFox 浏览器,对应的驱动为 geckodriver,具体的安装步骤就是先安装 FireFox 浏览器,然后在这里下载与浏览器版本相应的 geckodriver,并且在环境变量 PATH 中添加 geckodriver 的路径。

第二种方法对应的源码文件为 download_with_selenium.py

第二种方法的源码中主要有两个方法: get_image_links和,,第一个方法是获取所有图片链接并写入到文件中,第二个方法则是下载第一个方法获取的文件中的图片;在测试时,第二个方法常常会卡住,原因可能是网络的不稳定,也可能是图片服务器那边的反爬虫机制,代码中没有捕获到 Exception, 因此后面对第二个方法进行了改进,并将新的方法写到文件 download_images_with_time_limit.py

新的方法主要是限制 HTTP 请求的最大耗时,超过这个时间就会抛出异常,实现是通过系统的 signal 来中断进程的,并且用了 SIGALRM 这个信号,而这个信号只在 unix-like 系统中,因此 Windows 无法运行这个脚本。

SIGALRM 在 python 中的用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import signal, os

def handler(signum, frame):
print 'Signal handler called with signal', signum
raise IOError("Couldn't open device!")

try:
# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
exception IOERROR:
# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)
finally:
signal.alarm(0) # Disable the alarm