原创

Python 爬虫6——Scrapy的安装和使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://linsh-tech.blog.csdn.net/article/details/52122549

        前面我们简述了使用Python自带的urllib和urllib2库完成的一下爬取网页数据的操作,但其实能完成的功能都很简单,假如要进行复制的数据匹配和高效的操作,可以引入第三方的框架,例如Scrapy便是比较常用的爬虫框架。


一、Scrapy的安装:

1.最简单的安装方式:

        根据官方主页的指导:http://www.scrapy.org/

        使用pip来安装python相关插件其实都很简单,当然用这个办法安装Scrapy也是最为简单的安装方式,仅需在命令行窗口输入:

pip install scrapy

        

        检验是否安装成功,通过在命令行中输入:scrapy,即可查看当前scrapy的版本为Scrapy 1.1.1

       

        也有可能在使用pip安装scrapy的时候出现错误,我就是出现了lxml插件和PyDispatcher插件找不到的问题,缺啥就装啥,就这么简单。遇到这样的情况的话可以单独下载这两个插件安装完成之后再重新安装scrapy即可:

        lxml下载地址:https://pypi.python.org/pypi/lxml/3.3.1

        PyDispatcher下载地址:https://pypi.python.org/pypi/PyDispatcher/


二、使用步骤:

1.创建一个Scrapy项目:

        使用Scrapy提供的模板来创建一个工程,在命令行中定位到保存测试工程的目录下,使用创建指令创建工程:

scrapy startproject MyTest
        最后MyTest是工程文件名,然后在资源管理中可以看到指定目录下已经多了一个项目文件夹,项目的结果树如下:

        

        每个文件的作用:

  • scrapy.cfg:                 项目配置文件
  • MyTest/:                    项目python模块, 呆会代码将从这里导入
  • MyTest/items.py:       项目items文件
  • MyTest/pipelines.py: 项目管道文件
  • MyTest/settings.py:   项目配置文件
  • MyTest/spiders:         放置spider的目录


2.定义要提取的Item:

        Item其实就是用来保存装载从网页上爬去数据的容器,就像是Python中的一个字典或者是其他语言中的一个结构体,但它提供更多的保护,比如:对未定义的字段填充以防止拼写错误。

        为了方便模块化管理,scrapy模板中把所有的自定义Item类都在items.py中定义,我们打开上面创建的MyTest项目中的items.py即可看到模板样例:

# -*- coding: utf-8 -*-

import scrapy

class MytestItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass
        如上述代码,定义一个类,该类需要继承自scrapy.Item类,而类中的属性则是scrapy.Field类型。假设我们要爬去某个站点的名称、链接地址和描述这三个数据,我们可以在items.py中定义一个类InfoItem:

from scrapy import Item,Field


class InfoItem(Item):
    # define the fields for your item here like:
    title = Field()
    link = Field()
    desc = Field()


3.定义一个Spider来爬行站点,并提取Items:

        完成了Item的定义之后,接下来我们就需要定义一个Spider类,它就像是一只用来爬去指定url或者是url组(多个url)的网站内容的爬虫,为我们爬取信息。

        在Scrapy中定义一个Spider类,需要继承自scrapy.spider.BaseSpider类,并且有三个必须重写的属性,分别是:

  • name:当前定义的爬虫的别名,也是它的唯一标识,所以定义的每个Spider类的name属性都必须是唯一的;
  • start_urls:爬虫开始爬取数据的URL列表,爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些URLS开始。其他子URL将会从这些起始URL中继承性生成;
  • parse():爬虫的方法,调用时传入从每一个URL传回的Response对象作为参数,response将会是parse方法的唯一的一个参数。这个方法负责解析返回的数据、匹配抓取的数据(解析为item)并跟踪更多的URL。
        根据Scrapy模板创建的MyTest工程目录结构来看,自定义的Spider类应存放在spiders目录下面:
# -*- coding: utf-8 -*-

from scrapy import Spider

class TestSpider(Spider):
    name = "lsh"
    allowed_domains = ["baidu.com"]
    start_urls = [
        "https://www.baidu.com",
        "http://www.66ds.com/"
    ]

    def parse(self,response):
        print('response==================')
        可以使用一下指令来检测我们定义的爬虫是否正常:
scrapy crawl lsh
        上述指令的最后一个参数,其实就是我们定义爬虫是给name属性所赋的值,这就是为什么每个爬虫的name属性都必须不重复,因为启动时会出现冲突。
        继承自Spider类的爬虫工作的原理:scrapy为爬虫的start_urls属性的每个URL创建一个scrapy.http.Request对象,并指定该爬虫的parse()方法作为其回调函数。这些Request在爬虫开始工作的时候被调用,然后将网络请求获得的结果Response对象传给parse()方法,从而将每个URL的结果反馈给爬虫。

注:执行以上指令的时候,我的爬虫程序出现了以下输出结果:Unhandled error in Deferred
        
        查看打印结果最后面的内容:ImportError: No module named win32api
        
        发现是缺少了pywin32插件,那么我们直接下载当前python版本对应的pywin32插件来安装即可,这里我下载的是:pywin32-218.win-amd64-py2.7.exe
        安装完成后再次输入“scrapy crawl lsh”,得到正确的结果如下:
        
        从上图也可看到parse()方法中的输出内容“response==================”,说明parse()方法被调用到了。

        修改一下爬虫的内容为:
# -*- coding: utf-8 -*-

from scrapy import Spider

class TestSpider(Spider):
    name = "lsh"
    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]
        open(filename,'wb').write(response.body)
        运行指令scrapy crawl lsh,发现运行结束后再项目根目录下多出了两个文件Books和Resources,这两个文件里面就是strat_urls中URL对应的页面内容:
        

4.定义一个Item Pipeline用于存储提取的Items:

a.提取Item:

        选择器:其实从网页中提取信息的方法有很多,在scrapy中采用的方法是一种叫做XPath selector的机制。下面列举几个简单的XPath参数表达式例子:

  • /html/head/title: 选择HTML文档<head>元素下面的<title> 标签。
  • /html/head/title/text(): 选择前面提到的<title> 元素下面的文本内容
  • //td: 选择所有 <td> 元素
  • //div[@class="mine"]: 选择所有包含 class="mine" 属性的div 标签元素
        为了方便使用XPath,scrapy提供了XPathSelector类,而且分成了两种实现方式:HTMLXPathSelector(解析Html数据)XMLXPathSelector(解析Xml数据),使用这两种方式都需要一个Response对象对他们进行实例化操作。

        由于Selector对象展示了文档的节点结构,所以第一个被实例化的selector必定与根节点或者整个项目有关。

        Selector类为我们提供了几个常用的方法:

  • path():返回selectors列表,每个selector表示一个xpath参数表达式选择的节点;
  • extract():返回一个Unicode字符串,该字符串是XPath返回的数据;
  • re():返回Unicode字符串列表,字符串作为参数由正则表达式提取出来
        shell中测试XPath:关于Selector类的功能可以使用scrapy内构的shell来测试,但需要依赖于IPython插件:IPython下载地址,安装完毕后在命令行输入一下指令:
scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
        这里我们可以得到一下结果:
        
        得到的数据中包含了:crawler、item、request、response、setting和spider这六项数据,但其实我们需要用到的只是response中的数据,因为里面存放着URL页面的响应数据,其中response.body存放的是html源码。response中有几个常用的方法:xpath()就是选择器,而extract()方法则会返回html标签之间的unicode内容,re()则是调用正则的接口(我恨正则)
        直接在命令行查询结果:
        
        response.xpath()返回的是一个selector列表,所以可以对其中的元素使用xpath、extract等函数进行更详细更深的节点的筛选,例如:
>>> response.xpath('//title')[0].xpath('text()').extract()
[u'DMOZ - Computers: Programming: Languages: Python: Books']

b.定义Item Pipeline:

        通过上述操作,我们清楚了如何使用XPath()来解析response返回的URL页面结果,那么我们接下来需要做的就是把这些数据存放到先前定义好的Item结构中,接下来我们需要查看response.body的页面源码,确定我们所需要内容在源码中的节点位置:

        我们需要的数据在一个 <ul>元素中,而且是第二个<ul>,我们可以通过如下命令选择每个在网站中的<li>元素:

response.xpath('//ul/li')
        获取网站描述:

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

        获取网站标题:

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

        获取网站链接:

response.xpath('//ul/li/a/@href').extract()
       根据上述分析,我们可以改写我们之前定义的TestSpider爬虫的parse()方法的内容:

    def parse(self,response):
        for sel in response.xpath('//ul/li'):
            item = InfoItem()
            item['title'] = sel.xpath('a/text()').extract()
            item['link'] = sel.xpath('a/@href').extract()
            item['desc'] = sel.xpath('text()').extract()
            print item['title'],item['link'],item['desc']
        使用之前在items.py中定义的InfoItem类创建的Item对象来保存爬取的结果,并打印出来,当然使用items.py的内容需要将其import到当前脚本中,修改后的TestSpider类如下:

# -*- coding: utf-8 -*-

from scrapy import Spider
from MyTest import items

class TestSpider(Spider):
    name = "lsh"
    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 = items.InfoItem()
            item['title'] = sel.xpath('a/text()').extract()
            item['link'] = sel.xpath('a/@href').extract()
            item['desc'] = sel.xpath('text()').extract()
            print item['title'],item['link'],item['desc']
        在命令行中输入“scrapy crawl lsh”进行一次爬取操作,得到的输出结果如下:
        
        由于response.xpath('//ul/li')得到的是selectors列表,所以每个selector对应一个InfoItem数据,多个数据其实可以用一个数组来保存,如下改造:

    def parse(self,response):
        item_list = []
        for sel in response.xpath('//ul/li'):
            item = items.InfoItem()
            item['title'] = sel.xpath('a/text()').extract()
            item['link'] = sel.xpath('a/@href').extract()
            item['desc'] = sel.xpath('text()').extract()
            #print item['title'],item['link'],item['desc']
            item_list.append(item)
        return item_list
         

c.保存爬取结果:

        之前的处理,我们最后爬取到的关键数据就是item_list中的数据,假如我们希望把这份数据保存下来,在运行爬虫爬取数据的时候在输入以下指令取代原来的“scrapy crawl lsh”:

scrapy crawl lsh -o item_list.json -t json
        这样,item_list中的数据将以json的格式保存在当前目录下面的一个新生成的.json文件中:

        

        查看该文件中的内容,即为爬虫所得数据。



文章最后发布于: 2016-08-10 14:52:06
展开阅读全文
0 个人打赏

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览