Tutorial I: First Spider

在这个tutorial中,我们的爬取目标为: quotes.toscrape.com ,在此特别感谢 scrapinghub 提供了这个测试爬虫的网站。

我们的需求为爬取网站中所有的quotes并以json的形式保存下来,每个quote包含如下几个字段:

名称 含义
text quote的内容
author quote作者
author_url 作者的相关链接
tags quote的标签列表

例如对于这个quote:

_images/quote_sample.png

我们得到的json数据为:

{
    "text": "“I have not failed. I've just found 10,000 ways that won't work.”",
    "author": "Thomas A. Edison",
    "author_url": "http://quotes.toscrape.com/author/Thomas-A-Edison",
    "tags": ["edison", "failure", "inspirational", "paraphrased"]
}

Spider Overview

我们编写的spider需要继承 xpaw.Spider 类,需要实现的功能包括:

  • 生成初始入口链接
  • 从爬取的网页中提取出所需的数据和后续待爬取的链接

我们首先给出spider的完整代码,然后再逐一进行解释:

from urllib.parse import urljoin
import json

from xpaw import Spider, HttpRequest, Selector, run_spider


class QuotesSpider(Spider):
    quotes = []

    def start_requests(self):
        yield HttpRequest('http://quotes.toscrape.com/', callback=self.parse)

    def parse(self, response):
        selector = Selector(response.text)
        for quote in selector.css('div.quote'):
            text = quote.css('span.text')[0].text
            author = quote.css('small.author')[0].text
            author_url = quote.css('small+a')[0].attr('href')
            author_url = urljoin(str(response.url), author_url)
            tags = quote.css('div.tags a').text
            self.quotes.append(dict(text=text, tags=tags,
                                    author=author, author_url=author_url))
        next_page = selector.css('li.next a')
        if len(next_page) > 0:
            next_page_url = urljoin(str(response.url), next_page[0].attr('href'))
            yield HttpRequest(next_page_url, callback=self.parse)

    def close(self):
        with open('quotes.json', 'w') as f:
            json.dump(self.quotes, f, ensure_ascii=False, indent=4)


if __name__ == '__main__':
    run_spider(QuotesSpider, log_level='DEBUG')

Start Requests

xpaw在加载spider后会调用其 start_requests 函数来获取整个爬取过程的入口链接,我们需要在该函数中生成入口链接并用HttpRequest进行封装。 在这个任务中,我们从网站首页开始即可遍历所有quotes所在的网页,因此入口链接选择网站的首页即可。

def start_requests(self):
    yield HttpRequest('http://quotes.toscrape.com/', callback=self.parse)

Note

start_requests 函数的返回值需为可迭代对象,如tuple, list, generator等。

HttpRequest的 callback 用来指定该request对应的response由哪个函数来处理。

Note

callback 只能指定为spider自身的成员函数。

Storing Data

在这个任务中,我们在spider的 close 函数中完整了数据的保存。 当爬取工作完成后,xpaw会调用spider的 close 函数 (如果存在的话),因此我们借机在该函数中将所有爬取到的quotes以json的格式写入到文件中。

def close(self):
    with open('quotes.json', 'w') as f:
        json.dump(self.quotes, f, ensure_ascii=False, indent=4)

Running Spider

我们通过xpaw内置的 run_spider 函数来运行spider,函数的第一个参数为spider类,相关配置可以通过关键词参数的形式进行设置。 例如这里我们通过 log_level='DEBUG' 设定日志的级别为 DEBUG 。 具体的配置项可参考 Settings

if __name__ == '__main__':
    run_spider(QuotesSpider, log_level='DEBUG')

运行我们的spider后会在同级目录下生成了quotes.json文件,打开即可看到爬取的quotes数据。