最近面临一个采集语料的任务,要求以百度搜索为入口,从搜索结果中检索到需要的语料。这样一来,面临的情况就相当复杂,于是好好研究了一下自动化测试工具Selenium,用这玩意儿做爬虫简直是万能的。可以把它当成一个浏览器的控制工具,也就是说,只要浏览器可以访问的页面,都可以爬下来。Selenium的使用不算复杂,但是使用的过程中发现,这里面的坑真不是一般的多!这篇文章其实更适合叫做 “Python爬虫踩坑记” ,因为每条经验都是踩坑踩!出!来!的!!!啊……
一、前期准备
1、安装Selenium
1 | pip install selenium |
2、安装lxml
lxml是一个用来解析html文件的包,可以很方便地通过xpath语法定位html中的标签和元素。安装也很简单,pip一下就好了。
1 | pip install lxml |
3、安装浏览器及driver
推荐Selenium搭配Chrome使用。
在我的系统(OpenSuse Leap 42.2)上,使用Selenium(version:3.4.3)搭配PhantomJS和Firefox都会出现一个奇怪的问题,就是在访问某些页面的时候会卡住,既不报错也不返回结果,尝试使用 implicitly_wait()、set_page_load_timeout()、set_script_timeout() 几个函数设置超时都没效果,而且更换User-Agent之后也没有用,换用Chrome之后问题消失。
Windows用户在安装Chrome时,需要注意只能安装 32位版本 (因为稍后需要的chromedriver只支持32位版),并且 不要 更改Chrome默认的安装路径,不然将无法使用。之后,需要下载一个chromedriver ,最新版是2.31,原下载地址被墙,好在我们有镜像:
http://npm.taobao.org/mirrors/chromedriver/2.31/
下载好之后,
Windows用户 :在C盘新建一个chromedriver文件夹,并把chromedriver.exe这个文件放进去。然后在环境变量(PATH)中添加“C:\chromedriver\”。
Linux用户 :把chromedriver文件放入/usr/bin/路径中。
4、测试
在Python交互环境中输入如下代码:
1 | from selenium import webdriver |
这时,桌面上应该会打开一个空白的Chrome浏览器窗口。继续输入:
1 | driver.get("http://www.baidu.com") |
就打开了百度的主页面。
如果出现异常,请检查如上步骤是否做好。或者也可以在下方留言,反正看我博客的人也不多……
二、网页及xpath简介
1、关于网页
爬虫的目的是为了在网页上爬取有用的信息,这也就要求我们要对网页的组成最起码有基础的了解。基本上每种浏览器都提供了查看网页源代码的方式,在一张网页上点击右键,一般就可以找到类似的选项。这时,可以看到具有如下基本结构的代码:
1 | <html> |
这是HTML(超文本标记语言)的基本结构,一个 <…> 叫做一个标签,标签一般是成对出现的,比如 <html> 和 </html>,带有斜杠的这种叫做闭合标签。每种标签具有不同的意义,比如:
- <html> 与 </html> 之间的文本描述网页
- <body> 与 </body> 之间的文本是可见的页面内容
- <h1> 与 </h1> 之间的文本被显示为标题
- <p> 与 </p> 之间的文本被显示为段落
浏览器就是根据这样的成对的标签,来加载每一个网页的。
标签一般会带有属性,比如:
1 | <title lang="en">Harry Potter</title> |
title标签就带有一个“lang”属性,且属性的值为“en”。
我们的目的是为了爬取信息,以上内容理解就可以,标签的意义并不需要识记。
2、关于xpath
我们通过爬虫爬取下来的网页,也具有如上的基本结构。那么,如何通过这些HTML标签,快速地定位到我们所需要的信息呢?
上节中的HTML代码可以看成具有树型的结构,如下图所示
在这个树形结构中,每对标签可以看做是一个 节点 。比如 head 是 h1 的 父节点 ,而 h1 是 head 的 子节点。xpath就提供了一种简单的语法,来解析HTML的这种树型结构。常用的xpath选取节点的方式如下:
选取符号 | 含义 |
---|---|
/ | 从根节点开始选取 |
// | 选择当前节点以下的节点,不考虑节点所处的绝对位置 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
text() | 选取当前节点下的文字 |
我们来看一个实例:
1 |
|
在上面这段XML代码中(如果读者不明白HTML和XML有什么差别,就把它们当成一样的好了),可以使用诸如如下的方式选取内容:
表达式 | 含义 |
---|---|
/bookstore/book/author/text() | 选取author节点下的文字内容 |
//author/text() | 选取author节点下的文字内容 |
//titile[@lang=’en’]/text() | 选取含有“lang”属性且属性值为“en”的title节点下的文字内容 |
//title[contains(@lang, ‘en’)]/text() | 选取属性“lang”中包含“en”字符的title节点下的文字内容 |
//title/@lang | 选取title的属性“lang”的值 |
以上是比较常用的xpath语法。
三、第一个爬虫
现在可以使用上面的工具,实现一个简单的爬虫了。我们以爬取豆瓣读书页面为例。
打开豆瓣读书的首页,可以看到有一个名为“最受关注图书榜”的栏目,栏目中共有十本书,以及与书相关的评论。我们的目的就是获取书名,以及评论。
在页面空白处点击鼠标右键,选择“检查元素”,可以在右方弹出检查页面元素的小窗口。
把鼠标放在右侧的代码上,左侧就会用阴影区域显示出当前代码对应的内容。然后通过点击代码左侧折行的小三角,就可以一步一步定位到我们需要找的代码。
通过检查我们可以发现,我们需要的信息处于这样的结构中:
1 | <div class="section popular-books"> |
不重要的部分我使用省略号略去,而“XXX”则代表我们需要提取出来的内容。使用xpath表示标题及评论内容为:
标题://div[@class='section popular-books']//li//div[@class='info']//h4[@class='title']//text()
评论://div[@class='section popular-books']//li//div[@class='info']//p[@class='reviews']//text()
需要注意的是,“<li>”标签表示的是列表项,因此我们可以先提取所有的“<li>”标签,然后在循环提取十个标题和评论就可以了。代码实现如下:
1 | #! /usr/bin/env python3 |
这样,一个简单的爬虫就写好了。但是显然它还比较简陋,代码也比较丑,还有许多需要改进的地方。下一节将记录如何改进爬虫,使它变得更强大。