当前位置:嗨网首页>书籍在线阅读

15-编写爬虫

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

3.3.2 编写爬虫

我们已经在半路上了。现在,我们需要编写爬虫。通常,我们会为每个网站或网站的一部分(如果网站非常大的话)创建一个爬虫。爬虫代码实现了完整的UR2IM流程,我们很快就可以看到。

什么时候使用爬虫,什么时候使用项目呢?项目是由 `Item` 和若干爬虫组成的。如果有很多网站,并且需要从中抽取相同类型的 `Item` ,比如:房产,那么所有这些网站都可以使用同一个项目,并且为每个源/网站使用一个爬虫。反之,如果要处理图书及房产这两种不同的源时,则应该使用不同的项目。

当然,可以在文本编辑器中从头开始创建一个爬虫,不过为了减少一些输入,更好的方法是使用 scrapy genspider 命令,如下所示。

$ scrapy genspider basic web
Created spider 'basic' using template 'basic' in module:
 properties.spiders.basic

现在,如果再次运行 tree 命令,就会注意到与之前相比唯一的不同是在 properties/spiders 目录中增加了一个新文件 basic.py 。前面的命令所做的工作就是创建了一个名为 "basic" 的“默认”爬虫,并且该爬虫被限制为只能爬取 web 域名下的 URL 。如果需要的话,可以很容易地移除这个限制,不过目前来说没有问题。爬虫使用 "basic" 模板创建。你可以通过输入 scrapy genspider-l 来查看其他可用的模板,然后在执行 scrapy genspider 时,通过 -t 参数,使用任意其他模板创建爬虫。在本章稍后的部分,我们将会看到一个示例。

Scrapy有许多子目录。我们一般假设你位于包含 `scrapy.cfg` 文件的目录中。这是项目的“顶级”目录。现在,每当我们引用Python“包”和“模块”时,它们就是以映射目录结构的方式设置的。比如,输出提到了 `properties.spiders.basic` ,就是指 `properties/spiders` 目录中的 `basic.py` 文件。我们早前定义的 `PropertiesItem` 类是在 `properties.items` 模块中,该模块对应的就是 `properties` 目录中的 `items.py` 文件。

如果查看 properties/spiders/basic.py 文件,可以看到如下代码。

import scrapy
class BasicSpider(scrapy.Spider):
  name = "basic"
  allowed_domains = ["web"]
  start_urls = (
    'http://www.web/',
  )
  def parse(self, response):
    pass

import 语句能够让我们使用Scrapy框架中已有的类。下面是扩展自 scrapy.SpiderBasicSpider 类的定义。通过“扩展”的方式,尽管我们实际上没有写任何代码,但是该类已经“继承”了Scrapy框架中的 Spider 类的相当一部分功能。这样,就可以只额外编写少量的代码行,而获得一个完整运行的爬虫了。然后,我们可以看到一些爬虫的参数,比如它的名字以及我们允许其爬取的域名。最后是空函数 parse() 的定义,该函数包含了两个参数,分别是 selfresponse 对象。通过使用 self 引用,我们就可以使用爬虫中感兴趣的功能了。而另一个对象 response ,我们应该很熟悉,它就是我们在scrapy shell中使用过的 response 对象。

这是你的代码——你的爬虫。不要害怕修改它,你不会真的把事情搞砸的。即使在最坏的情况下,你还可以使用 `rmproperties/spiders/basic.py*` 删除文件,然后再重新生成。尽情发挥吧!

好了,让我们开始改造吧。首先,要使用在scrapy shell中使用过的那个URL,对应地设置到 start_urls 参数中。然后,将使用爬虫预定义的方法 log() ,输出在基本字段表中总结的所有内容。修改后, properties/spiders/basic.py 的代码如下所示。

import scrapy
class BasicSpider(scrapy.Spider):
  name = "basic"
  allowed_domains = ["web"]
  start_urls = (
    'http://web:9312/properties/property_000000.html',
  )
  def parse(self, response):
    self.log("title: %s" % response.xpath(
      '//­*[@itemprop="name"][1]/text()').extract())
    self.log("price: %s" % response.xpath(
      '//­*[@itemprop="price"][1]/text()').re('[.0-9]+'))
    self.log("description: %s" % response.xpath(
      '//­*[@itemprop="description"][1]/text()').extract())
    self.log("address: %s" % response.xpath(
      '//­*[@itemtype="http://schema.org/'
      'Place"][1]/text()').extract())
    self.log("image_urls: %s" % response.xpath(
      '//­*[@itemprop="image"][1]/@src').extract())
我将会不时地修改格式,以便在屏幕和纸张中都能很好地显示。这并不意味着它有什么特殊的含义。

等了这么久,终于到了运行爬虫的时候了。我们可以使用命令 scrapy crawl 以及爬虫的名称来运行爬虫。

$ scrapy crawl basic
INFO: Scrapy 1.0.3 started (bot: properties)
...
INFO: Spider opened
DEBUG: Crawled (200) <GET http://...000.html>
DEBUG: title: [u'set unique family well']
DEBUG: price: [u'334.39']
DEBUG: description: [u'website...']
DEBUG: address: [u'Angel, London']
DEBUG: image_urls: [u'.../images/i01.jpg']
INFO: Closing spider (finished)
...

非常好!不要被大量的日志行吓倒。我们将会在后续的章节中更详细地研究其中的一部分,不过对于现在而言,只需要注意到所有使用XPath表达式收集到的数据确实能够通过这个简单的爬虫代码抽取出来就可以了。

让我们再来试验一下另一个命令: scrapy parse 。它允许我们使用“最合适”的爬虫来解析参数中给定的任意URL。我不喜欢抱有侥幸心理,所以我们使用它结合--spider参数来设置爬虫。

$ scrapy parse --spider=basic http://web:9312/properties/property_000001.
html

你会看到输出和之前是相似的,只不过现在是另一套房产。

`scrapy parse` 同样也是一个相当方便的调试工具。在任何情况下,如果你想“认真”抓取的话,应当使用主命令 `scrapy crawl` 。