scrapy使用手册

原文:https://doc.scrapy.org/en/latest/intro/tutorial.html

初识scrapy

scrapy是一个功能十分强大的爬虫应用框架,它可以从目标网站爬取结构化数据。所爬取的数据可以用作数据挖掘分析、信息处理、历史归档等。
scrapy最初是用作网络数据采集,后来随着scrapy框架的日益完善,也可用它获取API数据或者仅仅用作通用数据爬虫。

一个小例子带你走进scrapy

制作一个爬虫,爬取名言网站http://quotes.toscrape.com上的数据。
这个demo包括以下任务:

  • 创建一个scrapy工程
  • 写一个spider文件,爬取网页信息并提取数据
  • 使用命令行导出数据
  • 修改爬虫,自动爬取网页上包含的网页链接
  • 使用爬虫参数

创建scrapy工程

选择一个路径,你将在该路径下存储你的代码。按住shift+鼠标右键,进入cmd,输入以下代码:scrapy startproject tutorial。你将看到在该路径下新建一个tutorial文件,该文件夹包含以下文件:

tutorial/
    scrapy.cfg            # 部署配置文件

    tutorial/             # 项目的Python模块
        __init__.py

        items.py          # 定义items

        pipelines.py      # 项目管道文件

        settings.py       #项目设置文件

        spiders/          # 一个文件夹,将你的爬虫文件放在这个文件夹下
            __init__.py

第一个Spider文件

Spiders包含各种不同的类,它们定义了scrapy所要爬取的网站信息,继承于scrapy.Spider类,并定义了初始请求,如何选择后续链接,以及如何解析爬取的网页信息。
首先, 在tutorial/spiders目录下构建一个名为quotes_spider.py的文件,并写入如下代码:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)

可以看出,我们的spider继承scrapy.Spider类,并且定义一些属性和方法:

  • name:我们spider的名称,不同的spiders必须名称不同。
  • start_requests():必须返回一组可以迭代的请求(可以是请求列表或编写一个生成器函数),这些请求会告诉爬虫从哪个地方开始。后续的请求将依次从这些初始请求中生成。
  • parse():解析方法,在成功爬取网页之后用该方法进行数据提取,也可以找寻新的URL进行爬取。

运行spider

从项目最顶层的目录进入控制端,输入:scrapy crawl quotes
这个命令使我们刚添加的quotes爬虫得以运行。你会得到如下的输出:

... (omitted for brevity)
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Spider opened
2016-12-16 21:24:05 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:24:05 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (404) <GET http://quotes.toscrape.com/robots.txt> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-1.html
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-2.html
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Closing spider (finished)
...

然后,再查看一下当前目录,你会多出两个文件:quotes-1.html和quotes-2.html

刚刚发生了什么?

scrapy模块在接受Spider下的start_requests返回的scrapy.Request对象后,向目标网站发送请求,在得到响应后实例化response类,调用回调函数,response对象作为一个对象输入到回调函数中。

一种较为便捷的start_requests方法

相对于用start_requests() 方法从URLs中生成scrapy.Request对象,直接定义 start_urls类的属性更简单。我们可以定义start_urls为一个装有一系列URL的列表。接着,它会默认被start_requests()调用,从而生成爬虫的初始请求。
parse() 方法会被自动调用去处理这些请求,即使我们没有很明确地告诉Scrapy去做这些工作。这是由于parse()是scrapy的默认回调函数,在没有明确指定回调函数的情况下会被自动调用。

提取数据

学会如何利用scrapy去提取数据的最好的方法是学会用scrapy shell,即scrapy的脚本交互模式。(在cmd中)试着运行:

scrapy shell "http://quotes.toscrape.com/page/1/"
  • 注意:在Windows中URL被包含在双引号中(亲测,不加双引号也行)。

你的运行结果可能与下面这种情况类似:

[ ... Scrapy log here ... ]
2016-09-19 12:09:27 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x7fa91d888c90>
[s]   item       {}
[s]   request    <GET http://quotes.toscrape.com/page/1/>
[s]   response   <200 http://quotes.toscrape.com/page/1/>
[s]   settings   <scrapy.settings.Settings object at 0x7fa91d888c10>
[s]   spider     <DefaultSpider 'default' at 0x7fa91c8af990>
[s] Useful shortcuts:
[s]   shelp()           Shell help (print this help)
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects
[s]   view(response)    View response in a browser
>>>

我们可以利用response对象中的css元素来做数据提取,像这样:

>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]

所得的结果是一个类似于列表的SelectorList对象,它里面包含了从XML/HTML元素中抽离出来的selector对象,我们可对其做进一步的数据提取。如,我们要获得标题内容,可以这样做:

>>> response.css('title::text').extract()
['Quotes to Scrape']
  • 注意:我们需要在css query中加::text,意味着我们只想获得title元素中的内容,如果不加,则会得到如下结果:
    >>> response.css('title').extract()
    ['<title>Quotes to Scrape</title>']
  • 使用extract()会获得一个SelectorList,如果我们只需第一个结果,可以输入:
    >>> response.css('title::text').extract_first()
    'Quotes to Scrape'

    或者:
    >>> response.css('title::text')[0].extract()
    'Quotes to Scrape'
  • 使用.extract_first()可以避免IndexError错误,当不能匹配任何元素时,返回None。

除了extract()和extract_first(),我们可以使用正则去匹配元素。

>>> response.css('title::text').re(r'Quotes.*')
['Quotes to Scrape']
>>> response.css('title::text').re(r'Q\w+')
['Quotes']
>>> response.css('title::text').re(r'(\w+) to (\w+)')
['Quotes', 'Scrape']

在命令行输入:view(response),系统会自动调用默认浏览器打开已下载的网页。可以使用浏览器开发者工具或者火狐浏览器的firepath查看css元素。
同样地,我们也可以使用Xpath,例如:

>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').extract_first()
'Quotes to Scrape'

尽管XPath可能不如css那么流行,但在scrapy爬虫框架中,XPath的功能更为强大,如你可以搜索某网页的链接:select the link that contains the text “Next Page”。
我们回到刚才那个例子,我们需要提取网页上的title,author以及tags。在shell中输入:

>>>quote = response.css("div.quote")[0]
>>>title = quote.css("span.text::text").extract_first()
>>>title
'“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
>>> author = quote.css("small.author::text").extract_first()
>>> author
'Albert Einstein'

因为tags是一连串的字符串,我们使用.extract()函数获取。

>>> tags = quote.css("div.tags a.tag::text").extract()
>>> tags
['change', 'deep-thoughts', 'thinking', 'world']

从我们的爬虫中提取数据

到目前为止,我们只是从保存到本地的网页中获取数据,接下来我们在我们的spider中重新再做一遍。将前面的quotes_spider.py文件做如下修改:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
        'http://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

运行该爬虫,会看到如下输出:

2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['life', 'love'], 'author': 'André Gide', 'text': '“It is better to be hated for what you are than to be loved for what you are not.”'}
2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['edison', 'failure', 'inspirational', 'paraphrased'], 'author': 'Thomas A. Edison', 'text': "“I have not failed. I've just found 10,000 ways that won't work.”"}

爬虫数据存储

存储这些数据最简单的方法是Feed exports,可以使用以下语句:

scrapy crawl quotes -o quotes.json

这会生成quotes.json文件,包含所有的爬来的items。但是需注意同一个语句执行两次,会破坏json文件。这时,可以使用json lines:

scrapy crawl quotes -o quotes.jl

寻找链接

上述案例仅仅爬取两个网页的内容,如果你想爬取整个网站的名人名言,就需要多加一些link了。现在,让我们一起来看看,如何找到接下来要爬取的link。假设关键性的dom长这样:

<ul class="pager">
    <li class="next">
        <a href="/page/2/">Next <span aria-hidden="true">&rarr;</span></a>
    </li>
</ul>

我们可以在shell中输入以下信息:

>>> response.css('li.next a').extract_first()
'<a href="/page/2/">Next <span aria-hidden="true"></span></a>'

为了获取锚点元素,我们需要得到属性href,好在scrapy支持CSS衍生功能,能让我们获取属性的具体内容,具体如下:

>>> response.css('li.next a::attr(href)').extract_first()
'/page/2/'

所以,我们再次修改我们的quotes_spider.py文件,能使程序接着网页中的某个链接继续爬取网页上的信息。

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

        next_page = response.css('li.next a::attr(href)').extract_first()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

在上述代码中,在提取出数据后,parse()方法找寻链接作为下一个要爬取的网页,用urljoin()函数构建一个绝对URL,并且生成一个新的request对象,同时将自己作为下一个回调函数继续解析网页,如此反复直至网页里找不到link。

Requests的简写

可以使用response.follow来简化代码。

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('span small::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

        next_page = response.css('li.next a::attr(href)').extract_first()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

这里省去了URL地址拼接,但是需要注意response.follow仅仅返回一个Request实例,依然需要生成新的Request。
同时也可以传一个selector而不是字符串给respons.follow:

for href in response.css('li.next a::attr(href)'):
    yield response.follow(href, callback=self.parse)

对于<a>标签,这里有一个简写方式:因为respons.follow支持自动提取href属性,所以代码可以进一步简化:

for a in response.css('li.next a'):
    yield response.follow(a, callback=self.parse)

注意:response.follow(response.css('li.next a'))是无效的,因为response.css返回一个类似于列表一样、一系列的selector,而不是单一的selector。可以用上面的for循环或者response.follow(response.css('li.next a')[0])也是OK的。

更多的例子

有待下次更新吧

scrapy官方手册中文版是一本详细的指南,用于学习和使用Scrapy框架进行Web数据爬取和抓取。手册提供了对Scrapy的全面介绍,并包含了基本概念、安装步骤、示例代码和常见问题解答等内容。 首先,手册介绍了Scrapy框架的原理和架构,包括Spider、Item、Pipeline和Downloader等组件的作用和关系。读者可以了解到Scrapy是如何通过自动构建高性能的异步爬虫来获取网页数据的。 其次,手册提供了Scrapy的安装步骤和配置方法。读者可以根据手册中的指导,轻松地安装Scrapy并配置开发环境。同时,手册还介绍了Scrapy的依赖项和版本要求,确保读者能够正确地安装和使用Scrapy。 手册还详细介绍了Scrapy的使用方法和基本操作。读者可以了解如何创建一个爬虫项目、编写Spider、处理爬取的数据以及配置请求和响应信息等。手册提供了丰富的示例代码和详细的说明,帮助读者快速上手Scrapy。 此外,手册还介绍了Scrapy的高级功能和扩展机制。例如,手册详细介绍了如何使用中间件、自定义下载器以及使用Scrapy的命令行工具等。这些高级功能可以帮助用户更灵活地控制和定制Scrapy框架,满足各种复杂的爬取需求。 总的来说,scrapy官方手册中文版提供了对Scrapy框架全面的介绍和指导,适合初学者和有一定经验的开发者使用。读者可以通过学习手册,掌握Scrapy的基本概念和使用方法,并能够根据自己的需求进行灵活的扩展和定制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值