目录
前言
爬虫一定要会正则匹配。
这只是使用scrapy爬虫的记录,更多功能以及原理,请自行查阅scrapy框架官方文档(https://doc.scrapy.org/en/latest/)或者非官方中文文档(https://scrapy-chs.readthedocs.io/zh_CN/latest/);
这次记录使用的环境与工具:Python3.7.0+virtualenv(虚拟环境【第三方库】)+virtualenvwrapper(虚拟环境管理工具【第三方库】)+PyCharm(编辑器IDE)
scrapy vs requests+beautifulsoup (为什么选择scrapy)
两种爬虫模式比较:
1、requests和beautifulsoup都是库,scrapy是框架。
2、scrapy框架中可以加入requests和beautifulsoup。
3、scrapy基于twisted,性能是最大的优势。
4、scrapy方便扩展,提供了很多内置的功能。
5、scrapy内置的css和xpath selector非常方便,beautifulsoup最大的缺点就是慢。
总结起来,有俩点最重要:
1)scrapy使用twisted异步网络框架,类似nodejs,性能高;
2)scrapy内置的selector比beautifulsoup效率要高很多;
准备
更改国内镜像源
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
创建虚拟环境
安装库–request与scrapy框架
在PyCharm>>Terminal中执行request安装命令:pip install requests
,srapy安装命令:pip install scrapy
在安装scrapy框架的时候,会提示 error: Microsoft Visual C++ 14.0 is required. Get it with “Microsoft Visual C++ Build Tools”。但是这时候并不需要安装Microsoft Visual C++ 14.0,这是用因为scrapy需要依赖名为Twisted的扩展库。打开这个网站Python Extension Packages for Windows(https://www.lfd.uci.edu/~gohlke/pythonlibs/,以后缺少什么库大多来这里找),找到Twisted,根据python版本与系统的位数来下载whl文件,然后打开到该文件的目录,在项目的虚拟环境下,执行安装命令:
pip install Twisted‑18.7.0‑cp37‑cp37m‑win_amd64.whl
,Twisted安装成功后,再次安装scrapy框架即可。
使用scrapy框架创建爬虫项目
scrapy只是一个框架,现在要使用这个框架去创建一个爬虫项目,这个项目我命名为ArticleSpider
目录结构
1)scrapy.cfg: 项目的配置文件,现在可以先忽略。
2)ArticleSpider/: 该项目的python模块。
3)ArticleSpider/items.py: 项目中的item文件。
Item 是保存爬取到的数据的容器;其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。
类似在ORM中做的一样,可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个Item。
首先根据需要从https://www.zhihu.com/people/huangxiaoguai/answers(我的知乎回答url)获取到的数据对item进行建模。我们需要从知乎回答中获取回答内容,回答的时间,回答被点赞数。 对此,在item中定义相应的字段。编辑 ArticleSpider目录中的 items.py 文件:
4)ArticleSpider/pipelines.py: 项目中的pipelines文件。
Scrapy提供了pipeline模块来执行保存数据的操作。在创建的 Scrapy 项目中自动创建了一个 pipeline.py 文件,同时创建了一个默认的 Pipeline 类。比如我们要把item提取的数据保存到mysql数据库,可以如下编写:
5)ArticleSpider/settings.py: 项目的设置文件。
settings.py是Scrapy中比较重要的配置文件,里面可以设置的内容非常之多。比如我们在前面提到的在pipelines.py中编写了把数据保存到mysql数据的class,那么怎么样才能使得这个class执行呢?就可以在settings设置,如下:
6)ArticleSpider/spiders/: 放置spider代码的目录。
这个很好理解,如下图,我们后面的示例,爬取豆瓣、微博、知乎的爬虫代码文件都存放在这个文件夹下的。
7)tutorial/middlewares.py:中间件,这块在很后面才会用到,先不介绍。
创建爬虫模板
需要一个文件来编写爬虫逻辑,这时候可以使用这条命令:scrapy genspider example example.com
来创建爬虫模板,其中example为创建的文件名,example.com为爬虫的网址,不需要写http://或者https://
创建的文件以及文件内容如图所示:
在scrapy中,我们把要爬取的目标网页的URL放在start_urls中,start_urls是可以存放多个url地址的
运行爬虫文件
爬虫文件是不能直接运行的,需要通过命令:scrapy crawl 爬虫逻辑文件名
才能运行
在运行的过程中,如果出现这个报错 import win32api ModuleNotFoundError: No module named ‘win32api’,是因为缺少安装名为pypiwin32的库,python无法调用Windows系统的api,运行命令:pip install pypiwin32
安装即可。
使用PyCharm进行代码调试
要调试jobbole文件,直接打断点是调试不了的,因为这个文件是要通过命令:scrapy crawl 爬虫逻辑文件名
才能运行,所以,这时候需要创建一个入口文件,通过调试这个入口文件用代码的方式模拟命令去执行对应的爬虫逻辑文件。入口文件还有一个好处,就是易于管理和执行爬虫文件。在这里,我把入口文件命名为main.py
,放到ArticleSpider项目根目录下
运行入口文件main,可以在控制台看到输出的信息跟执行cmd命令信息一样,就是成功的。
在爬虫文件处打断点,然后在入口文件main处执行debug(记住不是run!),就可以在爬虫文件处看到调试信息
当我们导入一个模块时:import xxx,默认情况下python解析器会搜索当前目录、已安装的内置模块和第三方模块,搜索路径存放在sys模块的path中,打印sys.path 返回的是一个路径列表!
该路径已经添加到系统的环境变量了,当我们要添加自己的搜索目录时,可以通过列表的append()方法;
对于模块和自己写的脚本不在同一个目录下,在脚本开头加sys.path.append(‘xxx’):
import sys
sys.path.append(’引用模块的地址')
这种方法是运行时修改,脚本运行后就会失效的。
另外一种方法是:
把路径添加到系统的环境变量,或把该路径的文件夹放进已经添加到系统环境变量的路径内。环境变量的内容会自动添加到模块搜索路径中。
网页元素选择器
网页的元素都是DOM树形结构,可以根据这种结构,去查找获取目标信息。这个时候需要一个工具快捷高效的定位到目标,而现在有两种不同方式的工具Xpath与CSS选择器,来实现需求。
Xpath
Xpath简介
XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言。XPath基于XML的树状结构,有不同类型的节点,包括元素节点,属性节点和文本节点,提供在数据结构树中找寻节点的能力。起初
XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSLT间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。
简单来说我们通过Xpath可以获取XML中的指定元素和指定节点的值。在网络爬虫中我们通过会把爬虫获取的HTML数据转换成XML结构,然后通过XPath解析,获取我们想要的结果。
接下来为大家分享以下xpath的表达式以及用法。
一.选取节点
Xpath使用路径表达式在XML文档中选取节点。节点是通过沿着路径来选取的,通过路径可以找到我们想要的节点或者节点范围。
表达式 |
描述 |
用法 |
说明 |
nodename | 选取此节点的所有子节点。 | xpath(‘span’) | 选取span元素的所有子节点 |
/ | 从根节点选取 | xpath(‘/div’) | 从根节点上选取div节点 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
|
xpath(‘//div’) | 从当前节点选取含有div节点的标签 |
. | 选取当前节点 | xpath(‘./div’) | 选取当前节点下的div标签 |
.. | 选取当前节点的父节点 | xpath(‘../’) | 回到上一级节点 |
@ | 选取属性 | xpath(“//div[@id=’1001’]”) | 获取div标签中,含有ID属性且值为1001的标签 |
二.谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
表达式描述 |
用法说明 |
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()<3] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang=’eng’] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
/bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
三. 通配符
XPath 通配符可用来选取未知的 XML 元素,通配指定节点。
表达式 |
描述 |
用法 |
说明 |
* | 匹配任何元素节点 | xpath(/div/*) | 选取div下的所有子节点 |
@* | 匹配任何属性节点 | xpath(/div[@*]) | 选取所有带属性的div节点 |
node() | 匹配任何类型的节点 | xpath(//div[@class=’tb_cls’]).node() | 选择标签为div且类属性为tb_cls的所有标签 |
四.多路径选择
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
用法 |
说明 |
xpath(//book/title |//book/price) | 选取 book 元素的所有 title 和 price 元素。 |
xpath(//title| //price) | 选取文档中的所有 title 和 price 元素 |
五.XPath 轴
轴可定义相对于当前节点的节点集。
表达式 |
描述 |
用法 |
说明 |
ancestor | 选取当前节点的所有先辈(父、祖父等) | xpath(//div[@id=’123’]/ancestor::*) | 选择标签为div且ID号为123的所有先辈标签 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身 | xpath(//div[@id=’123’]/ancestor-or-self::*) | 选择标签为div且ID号为123的所有先辈标签且包含自己 |
attribute | 选取当前节点的所有属性 | xpath(//div[@id=’123’]/attribute::class) | 选择标签为div且ID号为123的类属性名称 |
child | 选取当前节点的所有子元素 | xpath(//div[@id=’123’]/child::book) | 选择标签为div且ID号为123的所有子元素的为book 节点 |
descendant | 选取当前节点的所有后代元素(子、孙等) | xpath(./descendant::*) | 返回当前节点的所有后代节点(子节点、孙节点) |
following | 选取文档中当前节点结束标签后的所有节点 | xpath(./following::*) | 选取文档中当前节点结束标签后的所有节点 |
parent | 选取当前节点的父节点 | xpath(./parent::*) | 选取当前节点的父节点 |
preceding | 选取文档中当前节点的开始标签之前的所有节点 | xpath(//div[@id=’123’]/preceding::*) | 选择标签为div且ID号为123的开始标签之前的所有节点 |
preceding-sibling | 选取当前节点之前的所有同级节点 | xpath(//div[@id=’123’]/preceding-sibling::*) | 选择标签为div且ID号为123的之前的所有同级节点 |
self | 选取当前节点 | xpath(./self::*) | 选取当前节点 |
六.XPath 运算符
表达式 |
描述 |
用法 |
说明 |
+ | 加法 | 6 + 4 | 10 |
– | 减法 | 6 – 4 | 2 |
* | 乘法 | 6 * 4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | price=9.80 | 如果 price 是 9.80,则返回 true。
如果 price 是 9.90,则返回 false。 |
!= | 不等于 | price!=9.80 | 如果 price 是 9.90,则返回 true。
如果 price 是 9.80,则返回 false。 |
< | 小于 | price<9.80 | 如果 price 是 9.00,则返回 true。
如果 price 是 9.90,则返回 false。 |
<= | 小于或等于 | price<=9.80 | 如果 price 是 9.00,则返回 true。
如果 price 是 9.90,则返回 false。 |
> | 大于 | price>9.80 | 如果 price 是 9.90,则返回 true。
如果 price 是 9.80,则返回 false。 |
>= | 大于或等于 | price>=9.80 | 如果 price 是 9.90,则返回 true。
如果 price 是 9.70,则返回 false。 |
or | 或 | price=9.80 or price=9.70 | 如果 price 是 9.80,则返回 true。
如果 price 是 9.50,则返回 false。 |
and | 与 | price>9.00 and price<9.90 | 如果 price 是 9.80,则返回 true。
如果 price 是 8.50,则返回 false。 |
mod | 计算除法的余数 | 5 mod 2 | 1 |
七.常用的功能函数
使用功能函数能够更好的进行模糊搜索
表达式 |
描述 |
用法 |
说明 |
starts-with |
选取id值以ma开头的div节点 |
xpath(‘//div[starts-with(@id,”ma”)]‘) |
选取id值以ma开头的div节点 |
contains |
选取id值包含ma的div节点 |
xpath(‘//div[contains(@id,”ma”)]‘) |
选取id值包含ma的div节点 |
and |
选取id值包含ma和in的div节点 |
xpath(‘//div[contains(@id,”ma”) and contains(@id,”in”)]‘) |
选取id值包含ma和in的div节点 |
text() |
选取节点文本包含ma的div节点 |
xpath(‘//div[contains(text(),”ma”)]‘) |
选取节点文本包含ma的div节点 |
快捷优雅获取Xpath表达式
打开网页 》》按F12
调出调试页面 》》点击选择目标元素 》》点击鼠标右键 》》Copy 》》Copy Xpath,即可获取到目标元素Xpath表达式。
使用Xpath
接收返回信息的response对象中,有一个Xpath方法,对返回的网页进行选择:response.xpath()
获取的结果会带有当初选择目标时的HTML元素,但是目标是获取文字,那么,可以做Xpath表达式后加上text()
,表示获取文字,把HTML元素去掉。
CSS
CSS选择器的语法参考这里:CSS 选择器参考手册(http://www.w3school.com.cn/cssref/css_selectors.asp)。