我爱编程

爬虫-Scrapy 快速入门指南

2018-03-05  本文已影响0人  losangele

简介


    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

    其最初是为了 页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据或者通用的网络爬虫。

使用建议,爬取数据的时候为了防止ip地址被封禁,有以下几个建议:

1.修改配置文件伪造session信息。

2.抓取间隔时间尽量要长。

3.通过代理使用ip地址池,循环使用,避免使用一个地址。

4.请求透过Tor Browser,防止自身ip被禁。


安装


    由于scrapy依赖的安装包很多,所以推荐使用pip工具实现快速安装。安装命令如下:pip install Scrapy 。其他安装方式可以参考官方文档。

    注:先下载pip安装文件,下载地址:https://bootstrap.pypa.io/get-pip.py,然后运行pip安装命令:python get-pip.py。


实例


      将抓取quotes.toscrape.com网站数据,这是一个列出著名作家引用的网站。

    本教程将引导您完成这些任务:

    1.创建一个新的Scrapy项目

    2.编写爬虫抓取网站并提取数据

    3.使用命令行导出抓取的数据

    4.更改爬虫递归跟随链接

    5.使用爬虫参数


创建Scrapy项目


    选择工程存放目录,创建名为tutorial的工程,然后运行如下命令:scrapy startproject tutorial.

这将创建一个包含以下内容的tutorial目录:

tutorial/

    scrapy.cfg  # 部署配置文件

    tutorial/ #项目的Python模块,从这里导入你的代码

        __init__.py

        items.py  # 项目提取字段定义文件

        middlewares.py # 项目中间件文件,用于定义属于自己特殊应用的中间件

        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子类(QuotesSpider)scrapy.Spider定义了一些属性和方法:

    名称:爬虫名字。 它在项目中必须是唯一的,也就是说,不能为不同的爬虫设置相同的名称。

    start_requests():必须返回一个迭代请求(你可以返回一个请求列表或者写一个生成器函数),Spider将开始抓取它。 随后的请求将从这些初始请求中连续生成。

    parse():将被调用来处理为每个请求下载的响应的方法。 响应参数是TextResponse的一个实例,用于保存页面内容,并有更多有用的方法来处理它。

    parse()方法通常解析响应,将提取的数据提取为字符串,并找到新的URL来跟踪并创建新的请求(Request)。


如何启动爬虫


    在工程的同级目录运行命令:scrapy crawl quotes。

     该命令使用刚刚添加的名称引号运行该爬虫,该爬虫将向quotes.toscrape.com域发送一些请求。 你会得到类似于这样的输出:

...(omittedforbrevity)

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

....

    现在,检查当前目录中的文件。 您应该注意到已经创建了两个新文件:quotes-1.html和quotes-2.html,以及相应URL的内容,正如分析方法指示的那样。


爬虫运行的原理


    Scrapy安排由Spider的start_requests方法返回的scrapy.Request对象。 在收到每个响应后,它会实例化Response对象,并调用与请求相关的回调方法(在本例中为parse方法),将响应作为参数传递。

    除了实现从URL生成scrapy.Request对象的start_requests()方法外,您还可以使用URL列表定义start_urls类属性。 这个列表将被默认的start_requests()实现用来为你的爬虫创建初始请求:

import    scrapy

class    DmozSpider(scrapy.spiders.Spider):

    name="dmoz"

    allowed_domains=["dmoz.org"]

    start_urls=    ["http://www.dmoz.org/Computers/Programming/Languages/Python/Books/","http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"]   

    def    parse(self,response):    

        filename=response.url.split("/")[-2]

        with    open(filename,'wb')asf:

                f.write(response.body)

    该实例将调用parse()方法来处理这些URL的每个请求,即使没有明确告诉Scrapy这样做。 发生这种情况是因为parse()是Scrapy的默认回调方法,该方法在未显式分配回调的情况下针对请求调用。


提取数据


学习如何使用Scrapy提取数据的最佳方法是使用Scrapy shell,运行:

scrapy  shell  'http://quotes.toscrape.com/page/1/'

输出如下:

[...Scrapyloghere...]2016-09-1912:09:27[scrapy.core.engine]DEBUG:Crawled(200)<GEThttp://quotes.toscrape.com/page/1/>(referer:None)[s]AvailableScrapyobjects:[s]scrapyscrapymodule(containsscrapy.Request,scrapy.Selector,etc)[s]crawler<scrapy.crawler.Crawlerobjectat0x7fa91d888c90>[s]item{}[s]request<GEThttp://quotes.toscrape.com/page/1/>[s]response<200http://quotes.toscrape.com/page/1/>[s]settings<scrapy.settings.Settingsobjectat0x7fa91d888c10>[s]spider<DefaultSpider'default'at0x7fa91c8af990>[s]Usefulshortcuts:[s]shelp()Shellhelp(printthishelp)[s]fetch(req_or_url)Fetchrequest(orURL)andupdatelocalobjects[s]view(response)Viewresponseinabrowser>>>

查看包含 [dmoz] 的输出,可以看到输出的log中包含定义在 start_urls 的初始URL,并且与spider中是一一对应的。在log中可以看到其没有指向其他页面( (referer:None) )。

除此之外,更有趣的事情发生了。就像parse 方法指定的那样,有两个包含url所对应的内容的文件被创建了: Book , Resources 。

刚才发生了什么?

Scrapy为Spider的 start_urls 属性中的每个URL创建了 scrapy.Request 对象,并将 parse 方法作为回调函数(callback)赋值给了Request。

Request对象经过调度,执行生成 scrapy.http.Response 对象并送回给spider parse() 方法。

提取Item

Selectors选择器简介

从网页中提取数据有很多方法。Scrapy使用了一种基于 XPath 和 CSS 表达式机制: Scrapy Selectors。 关于selector和其他提取机制的信息请参考 Selector文档 。

这里给出XPath表达式的例子及对应的含义:

/html/head/title: 选择HTML文档中 <head> 标签内的 <title> 元素

/html/head/title/text(): 选择上面提到的 <title> 元素的文字

//td: 选择所有的 <td> 元素

//div[@class="mine"]: 选择所有具有 class="mine" 属性的 div 元素

上边仅仅是几个简单的XPath例子,XPath实际上要比这远远强大的多。 如果您想了解的更多,推荐官方文档。

为了配合XPath,Scrapy除了提供了 Selector 之外,还提供了方法来避免每次从response中提取数据时生成selector的麻烦。

Selector有四个基本的方法(点击相应的方法可以看到详细的API文档):

xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 。

css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表.

extract(): 序列化该节点为unicode字符串并返回list。

re(): 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。

在Shell中尝试Selector选择器

为了介绍Selector的使用方法,接下来将要使用内置的 Scrapy shell 。Scrapy Shell需要您预装好IPython(一个扩展的Python终端)。

您需要进入项目的根目录,执行下列命令来启动shell:

scrapy    shell    "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"

注解

当您在终端运行Scrapy时,请一定记得给url地址加上引号,否则包含参数的url(例如 & 字符)会导致Scrapy运行失败。

shell的输出类似:

[...Scrapyloghere...]2015-01-0722:01:53+0800[domz]DEBUG:Crawled(200)<GEThttp://www.dmoz.org/Computers/Programming/Languages/Python/Books/>(referer:None)[s]AvailableScrapyobjects:[s]crawler<scrapy.crawler.Crawlerobjectat0x02CE2530>[s]item{}[s]request<GEThttp://www.dmoz.org/Computers/Programming/Languages/Python/Books/>[s]response<200http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>[s]sel<Selectorxpath=Nonedata=u'<html lang="en">\r\n<head>\r\n<meta http-equ'>[s]settings<CrawlerSettingsmodule=<module'tutorial.settings'from'tutorial\settings.pyc'>>[s]spider<DomzSpider'domz'at0x302e350>[s]Usefulshortcuts:[s]shelp()Shellhelp(printthishelp)[s]fetch(req_or_url)Fetchrequest(orURL)andupdatelocalobjects[s]view(response)Viewresponseinabrowser>>>

当shell载入后,您将得到一个包含response数据的本地 response 变量。输入 response.body 将输出response的包体, 输出 response.headers 可以看到response的包头。

更为重要的是,当输入 response.selector 时, 您将获取到一个可以用于查询返回数据的selector(选择器), 以及映射到 response.selector.xpath() 、 response.selector.css() 的 快捷方法(shortcut): response.xpath() 和 response.css() 。

同时,shell根据response提前初始化了变量 sel 。该selector根据response的类型自动选择最合适的分析规则(XML vs HTML)。

来试试:

In[1]:sel.xpath('//title')

Out[1]:[<Selectorxpath='//title'data=u'<title>Open Directory - Computers: Progr'>]

In[2]:sel.xpath('//title').extract()

Out[2]:[u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>']

In[3]:sel.xpath('//title/text()')

Out[3]:[<Selectorxpath='//title/text()'data=u'Open Directory - Computers: Programming:'>]

In[4]:sel.xpath('//title/text()').extract()

Out[4]:[u'Open Directory - Computers: Programming: Languages: Python: Books']

In[5]:sel.xpath('//title/text()').re('(\w+):')

Out[5]:[u'Computers',u'Programming',u'Languages',u'Python']

提取数据

现在,来尝试从这些页面中提取些有用的数据。

您可以在终端中输入 response.body 来观察HTML源码并确定合适的XPath表达式。不过,这任务非常无聊且不易。您可以考虑使用Firefox的Firebug扩展来使得工作更为轻松。详情请参考 使用Firebug进行爬取 和 借助Firefox来爬取 。

在查看了网页的源码后,您会发现网站的信息是被包含在 第二个 <ul> 元素中。

可以通过这段代码选择该页面中网站列表里所有 <li> 元素:

sel.xpath('//ul/li')

网站的描述:

sel.xpath('//ul/li/text()').extract()

网站的标题:

sel.xpath('//ul/li/a/text()').extract()

以及网站的链接:

sel.xpath('//ul/li/a/@href').extract()

之前提到过,每个 .xpath() 调用返回selector组成的list,因此可以拼接更多的 .xpath() 来进一步获取某个节点。将在下边使用这样的特性:

forselinresponse.xpath('//ul/li'):title=sel.xpath('a/text()').extract()link=sel.xpath('a/@href').extract()desc=sel.xpath('text()').extract()printtitle,link,desc

注解

关于嵌套selctor的更多详细信息,请参考 嵌套选择器(selectors) 以及 选择器(Selectors) 文档中的 使用相对XPaths 部分。

在spider中加入这段代码:

import    scrapy    

class    DmozSpider(scrapy.Spider):

        name="dmoz"allowed_domains=["dmoz.org"]

        start_urls=    ["http://www.dmoz.org/Computers/Programming/Languages/Python/Books/","http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"]

def    parse(self,response):

    for    sel    in    response.xpath('//ul/li'):

        title=sel.xpath('a/text()').extract()

        link=sel.xpath('a/@href').extract()

        desc=sel.xpath('text()').extract()

        printtitle,link,desc

现在尝试再次爬取dmoz.org,您将看到爬取到的网站信息被成功输出:

scrapy    crawl    dmoz

使用item

Item 对象是自定义的python字典。 您可以使用标准的字典语法来获取到其每个字段的值。(字段即是之前用Field赋值的属性):

>>> item=DmozItem()>>> item['title']='Example title'>>> item['title']'Example title'

一般来说,Spider将会将爬取到的数据以 Item 对象返回。所以为了将爬取的数据返回,最终的代码将是:

import    scrapy    

from    tutorial.items    import    DmozItem    

class    DmozSpider(scrapy.Spider):

    name="dmoz"allowed_domains=["dmoz.org"]

    start_urls=    ["http://www.dmoz.org/Computers/Programming/Languages/Python/Books/","http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"]

def    parse(self,response):

    for    sel    in    response.xpath('//ul/li'):

        item=DmozItem()

        item['title']=sel.xpath('a/text()').extract()

        item['link']=sel.xpath('a/@href').extract()

        item['desc']=sel.xpath('text()').extract()

        yield    item

注解

您可以在 dirbot 项目中找到一个具有完整功能的spider。该项目可以通过 https://github.com/scrapy/dirbot 找到。

现在对dmoz.org进行爬取将会产生 DmozItem 对象:

[dmoz]DEBUG:Scrapedfrom<200http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>{'desc':[u' - By David Mertz; Addison Wesley. Book in progress, full text, ASCII format. Asks for feedback. [author website, Gnosis Software, Inc.\n],'link':[u'http://gnosis.cx/TPiP/'],'title':[u'Text Processing in Python']}[dmoz]DEBUG:Scrapedfrom<200http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>{'desc':[u' - By Sean McGrath; Prentice Hall PTR, 2000, ISBN 0130211192, has CD-ROM. Methods to build XML applications fast, Python tutorial, DOM and SAX, new Pyxie open source XML processing library. [Prentice Hall PTR]\n'],'link':[u'http://www.informit.com/store/product.aspx?isbn=0130211192'],'title':[u'XML Processing with Python']}

保存爬取到的数据

最简单存储爬取的数据的方式是使用 Feed exports:

scrapy    crawl    dmoz-oitems.json

该命令将采用 JSON 格式对爬取的数据进行序列化,生成 items.json 文件。

在类似本篇教程里这样小规模的项目中,这种存储方式已经足够。 如果需要对爬取到的item做更多更为复杂的操作,您可以编写 Item Pipeline 。 类似于我们在创建项目时对Item做的,用于您编写自己的 tutorial/pipelines.py 也被创建。 不过如果您仅仅想要保存item,您不需要实现任何的pipeline。

上一篇下一篇

猜你喜欢

热点阅读