咱们使用dmoz.org这个网站来做为小抓抓一展身手的对象。css
首先先要回答一个问题。html
问:把网站装进爬虫里,总共分几步?node
答案很简单,四步:python
好的,基本流程既然肯定了,那接下来就一步一步的完成就能够了。正则表达式
1.新建项目(Project)shell
在空目录下按住Shift键右击,选择“在此处打开命令窗口”,输入一下命令:json
其中,tutorial为项目名称。app
能够看到将会建立一个tutorial文件夹,目录结构以下:dom
下面来简单介绍一下各个文件的做用:scrapy
2.明确目标(Item)
在Scrapy中,items是用来加载抓取内容的容器,有点像Python中的Dic,也就是字典,可是提供了一些额外的保护减小错误。
通常来讲,item能够用scrapy.item.Item类来建立,而且用scrapy.item.Field对象来定义属性(能够理解成相似于ORM的映射关系)。
接下来,咱们开始来构建item模型(model)。
首先,咱们想要的内容有:
修改tutorial目录下的items.py文件,在本来的class后面添加咱们本身的class。
由于要抓dmoz.org网站的内容,因此咱们能够将其命名为DmozItem:
刚开始看起来可能会有些看不懂,可是定义这些item能让你用其余组件的时候知道你的 items究竟是什么。
能够把Item简单的理解成封装好的类对象。
3.制做爬虫(Spider)
制做爬虫,整体分两步:先爬再取。
也就是说,首先你要获取整个网页的全部内容,而后再取出其中对你有用的部分。
3.1爬
Spider是用户本身编写的类,用来从一个域(或域组)中抓取信息。
他们定义了用于下载的URL列表、跟踪连接的方案、解析网页内容的方式,以此来提取items。
要创建一个Spider,你必须用scrapy.spider.BaseSpider建立一个子类,并肯定三个强制的属性:
这里能够参考宽度爬虫教程中说起的思想来帮助理解,教程传送:[Java] 知乎下巴第5集:使用HttpClient工具包和宽度爬虫。
也就是把Url存储下来并依此为起点逐步扩散开去,抓取全部符合条件的网页Url存储起来继续爬取。
下面咱们来写第一只爬虫,命名为dmoz_spider.py,保存在tutorial\spiders目录下。
dmoz_spider.py代码以下:
allow_domains是搜索的域名范围,也就是爬虫的约束区域,规定爬虫只爬取这个域名下的网页。
从parse函数能够看出,将连接的最后两个地址取出做为文件名进行存储。
而后运行一下看看,在tutorial目录下按住shift右击,在此处打开命令窗口,输入:
运行结果如图:
报错了:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xb0 in position 1: ordinal not in range(128)
运行第一个Scrapy项目就报错,真是命运多舛。
应该是出了编码问题,谷歌了一下找到了解决方案:
在python的Lib\site-packages文件夹下新建一个sitecustomize.py:
再次运行,OK,问题解决了,看一下结果:
最后一句INFO: Closing spider (finished)代表爬虫已经成功运行而且自行关闭了。
包含 [dmoz]的行 ,那对应着咱们的爬虫运行的结果。
能够看到start_urls中定义的每一个URL都有日志行。
还记得咱们的start_urls吗?
http://www.dmoz.org/Computers/Programming/Languages/Python/Books
http://www.dmoz.org/Computers/Programming/Languages/Python/Resources
由于这些URL是起始页面,因此他们没有引用(referrers),因此在它们的每行末尾你会看到 (referer: <None>)。
在parse 方法的做用下,两个文件被建立:分别是 Books 和 Resources,这两个文件中有URL的页面内容。
那么在刚刚的电闪雷鸣之中到底发生了什么呢?
首先,Scrapy为爬虫的 start_urls属性中的每一个URL建立了一个 scrapy.http.Request 对象 ,并将爬虫的parse 方法指定为回调函数。
而后,这些 Request被调度并执行,以后经过parse()方法返回scrapy.http.Response对象,并反馈给爬虫。
3.2取
爬取整个网页完毕,接下来的就是的取过程了。
光存储一整个网页仍是不够用的。
在基础的爬虫里,这一步能够用正则表达式来抓。
在Scrapy里,使用一种叫作 XPath selectors的机制,它基于 XPath表达式。
若是你想了解更多selectors和其余机制你能够查阅资料:点我点我
这是一些XPath表达式的例子和他们的含义
以上只是几个使用XPath的简单例子,可是实际上XPath很是强大。
能够参照W3C教程:点我点我。
为了方便使用XPaths,Scrapy提供XPathSelector 类,有两种能够选择,HtmlXPathSelector(HTML数据解析)和XmlXPathSelector(XML数据解析)。
必须经过一个 Response 对象对他们进行实例化操做。
你会发现Selector对象展现了文档的节点结构。所以,第一个实例化的selector必与根节点或者是整个目录有关 。
在Scrapy里面,Selectors 有四种基础的方法(点击查看API文档):
3.3xpath实验
下面咱们在Shell里面尝试一下Selector的用法。
实验的网址:http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
熟悉完了实验的小白鼠,接下来就是用Shell爬取网页了。
进入到项目的顶层目录,也就是第一层tutorial文件夹下,在cmd中输入:
回车后能够看到以下的内容:
在Shell载入后,你将得到response回应,存储在本地变量 response中。
因此若是你输入response.body,你将会看到response的body部分,也就是抓取到的页面内容:
或者输入response.headers 来查看它的 header部分:
如今就像是一大堆沙子握在手里,里面藏着咱们想要的金子,因此下一步,就是用筛子摇两下,把杂质出去,选出关键的内容。
selector就是这样一个筛子。
在旧的版本中,Shell实例化两种selectors,一个是解析HTML的 hxs 变量,一个是解析XML 的 xxs 变量。
而如今的Shell为咱们准备好的selector对象,sel,能够根据返回的数据类型自动选择最佳的解析方案(XML or HTML)。
而后咱们来捣弄一下!~
要完全搞清楚这个问题,首先先要知道,抓到的页面究竟是个什么样子。
好比,咱们要抓取网页的标题,也就是<title>这个标签:
能够输入:
结果就是:
这样就能把这个标签取出来了,用extract()和text()还能够进一步作处理。
备注:简单的罗列一下有用的xpath路径表达式:
表达式 | 描述 |
---|---|
nodename | 选取此节点的全部子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
所有的实验结果以下,In[i]表示第i次实验的输入,Out[i]表示第i次结果的输出(建议你们参照:W3C教程):
固然title这个标签对咱们来讲没有太多的价值,下面咱们就来真正抓取一些有意义的东西。
使用火狐的审查元素咱们能够清楚地看到,咱们须要的东西以下:
咱们能够用以下代码来抓取这个<li>标签:
从<li>标签中,能够这样获取网站的描述:
能够这样获取网站的标题:
能够这样获取网站的超连接:
固然,前面的这些例子是直接获取属性的方法。
咱们注意到xpath返回了一个对象列表,
那么咱们也能够直接调用这个列表中对象的属性挖掘更深的节点
(参考:Nesting selectors andWorking with relative XPaths in the Selectors):
sites = sel.xpath('//ul/li') for site in sites: title = site.xpath('a/text()').extract() link = site.xpath('a/@href').extract() desc = site.xpath('text()').extract() print title, link, desc
3.4xpath实战
咱们用shell作了这么久的实战,最后咱们能够把前面学习到的内容应用到dmoz_spider这个爬虫中。
在原爬虫的parse函数中作以下修改:
注意,咱们从scrapy.selector中导入了Selector类,而且实例化了一个新的Selector对象。这样咱们就能够像Shell中同样操做xpath了。
咱们来试着输入一下命令运行爬虫(在tutorial根目录里面):
scrapy crawl dmoz
运行结果以下:
果真,成功的抓到了全部的标题。可是好像不太对啊,怎么Top,Python这种导航栏也抓取出来了呢?
咱们只须要红圈中的内容:
看来是咱们的xpath语句有点问题,没有仅仅把咱们须要的项目名称抓取出来,也抓了一些无辜的可是xpath语法相同的元素。
审查元素咱们发现咱们须要的<ul>具备class='directory-url'的属性,
那么只要把xpath语句改为sel.xpath('//ul[@class="directory-url"]/li')便可
将xpath语句作以下调整:
成功抓出了全部的标题,绝对没有滥杀无辜:
3.5使用Item
接下来咱们来看一看如何使用Item。
前面咱们说过,Item 对象是自定义的python字典,可使用标准字典语法获取某个属性的值:
做为一只爬虫,Spiders但愿能将其抓取的数据存放到Item对象中。为了返回咱们抓取数据,spider的最终代码应当是这样:
4.存储内容(Pipeline)
保存信息的最简单的方法是经过Feed exports,主要有四种:JSON,JSON lines,CSV,XML。
咱们将结果用最经常使用的JSON导出,命令以下:
-o 后面是导出文件名,-t 后面是导出类型。
而后来看一下导出的结果,用文本编辑器打开json文件便可(为了方便显示,在item中删去了除了title以外的属性):
由于这个只是一个小型的例子,因此这样简单的处理就能够了。
若是你想用抓取的items作更复杂的事情,你能够写一个 Item Pipeline(条目管道)。
这个咱们之后再慢慢玩^_^