python_new
  • Introduction
  • First Chapter
  • 一、python基础
    • 1.1 常识
      • sys
    • 1.2 基础语法(1)
    • 1.2 基础语法(2)
    • 1.3 常见问题求解
    • 1.4 算法
  • 二、爬虫
    • urllib库(1)
      • urllib库(2)
    • requests模块(1)
      • requests模块(2)
    • 2.1 爬虫基础(3)HTTP原理
    • 2.1 爬虫基础(4)会话和Cookies
    • 2.1 爬虫基础(5)数据存储
      • Mysql存储
      • MongoDB存储
      • Redis存储
    • 2.3 正则表达式
    • 2.4 解析库lxml
      • BeautifulSoup
      • pyquery(1)
      • pyquery(2)
    • 2.5 selenium(1)
    • 2.5 seleium(2)
    • 2.6 Json
    • 2.7 scrapy
      • scrapy(2)
    • 2.9 异步加载
    • 2.6 Splash
  • ORM框架
    • SQLAlchemy
  • Django
    • 1、初阶(一)
    • 初学:投票教程(一)
    • 初学:投票教程(二)
    • 初学:投票教程(三)
    • 初学:投票教程(总结)
    • 模型(一)
    • 模型(二)
    • 视图(一)
    • 视图(二)
    • 模板(一)
    • django实际使用笔记
  • 面试题收集总结
    • 数据结构原理
    • 算法篇
      • 排序
    • 题目篇
  • python数据分析
    • 基础了解(一)
    • 基础了解(二)
    • 基础了解(三)
  • 多线程
  • 深度学习
    • 疑问
  • keras(一)
  • 神经网络
  • 图像识别
  • Docker
    • 一、基础了解
Powered by GitBook
On this page

Was this helpful?

  1. 二、爬虫
  2. 2.7 scrapy

scrapy(2)

2、定义Item

Item是保存爬取到的数据的容器,其使用方法和python字典类似,并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。

首先根据需要从目标网站获取到的数据对item进行建模。 比如我们需要从网站dmoz中获取名字,url,以及网站的描述。 对此,在item中定义相应的字段。当我们爬取到相应的数据后,就存储到这个类里面。编辑 tutorial 目录中的 items.py 文件:

import scrapy

class Data(scrapy.Item):        # 根据目标数据定义的类,用来存储目标数据,主要是字典的形式,如data['title'] = '2'
    title = scrapy.Field()
    link = scrapy.Field()
    desc = scrapy.Field()

3、编写爬虫

spider是用户编写用于从单个网站(或者一些网站)爬取数据的类,其中包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容,提取生成Item的方法。

为了创建一个spider,必须继承scrapy.spider类,并且定义以下属性

  • name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。

  • start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。

  • parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。

以下是一个例子,应该保存在tutorial/spiders目录下的dmoz_spider.py文件中

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):
        filename = response.url.split("/")[-2]
        with open(filename, 'wb') as f:
            f.write(response.body)

进入项目的根目录,执行下列命令启动spider

scrapy crawl dmoz

该命令用于启动爬去dmoz.org的spider,之后得到输出

查看包含 [dmoz] 的输出,可以看到输出的log中包含定义在 start_urls 的初始URL,并且与spider中是一一对应的。在log中可以看到其没有指向其他页面( (referer:None) )。除此之外,更有趣的事情发生了。就像我们 parse 方法指定的那样,有两个包含url所对应的内容的文件被创建了: Book , Resources 。

4、过程

Scrapy为Spider的 start_urls 属性中的每个URL创建了 scrapy.Request 对象,并将 parse 方法作为回调函数(callback)赋值给了Request。Request对象经过调度,执行生成 scrapy.http.Response 对象并送回给spider parse() 方法。

5、提取Item

从网页中提取数据有很多方法。Scrapy使用了一种基于 XPath 和 CSS 表达式机制: Scrapy Selectors 。为了配合XPath,Scrapy除了提供了 Selector 之外,还提供了方法来避免每次从response中提取数据时生成selector的麻烦。Selector有四个基本的方法:

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

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

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

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

6、提取数据

这部分的工作主要是分析目标数据在源码中的位置,由此确定合适Xpath表达式,借助浏览器,如chrome的检查功能,可以简化这部分的工作。

网站的信息

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

网站的描述

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

等等,每个 .xpath() 调用返回selector组成的list,因此我们可以拼接更多的 .xpath() 来进一步获取某个节点

for sel in response.xpath('//ul/li'):
    title = sel.xpath('a/text()').extract()
    link = sel.xpath('a/@href').extract()
    desc = sel.xpath('text()').extract()
    print title, link, desc

然后在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()
            print title, link, desc

7、使用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

8、保存数据

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

scrapy crawl dmoz -o items.json

该命令将采用 JSON 格式对爬取的数据进行序列化,生成 items.json 文件。在类似本篇教程里这样小规模的项目中,这种存储方式已经足够。 如果需要对爬取到的item做更多更为复杂的操作,您可以编写 Item Pipeline 。 类似于我们在创建项目时对Item做的,用于您编写自己的 tutorial/pipelines.py 也被创建。 不过如果您仅仅想要保存item,您不需要实现任何的pipeline

三、命令行工具

Scrapy是通过 scrapy 命令行工具进行控制的。 这里我们称之为 “Scrapy tool” 以用来和子命令进行区分。 对于子命令,我们称为 “command” 或者 “Scrapy commands”。Scrapy tool 针对不同的目的提供了多个命令,每个命令支持不同的参数和选项。

1、创建项目

scrapy startproject myproject
# myproject是任意设定项目名称

2、工具命令

scrapy <command> -h

查看单个命令的详细内容

scrapy -h

查看所有可用命令

Scrapy提供了两种类型的命令。一种必须在Scrapy项目中运行(针对项目(Project-specific)的命令),另外一种则不需要(全局命令)。全局命令在项目中运行时的表现可能会与在非项目中运行有些许差别(因为可能会使用项目的设定)

  • 全局命令

startproject
settings
runspider
shell
fetch
view
version
  • 项目命令

crawl
check
list
edit
parse
genspider
deploy
bench

3、具体命令

  • genspider

可以使用提前定义好的模板来生成spider

示例

scrapy genspider -l
Available templates:
  basic
  crawl
  csvfeed
  xmlfeed

scrapy genspider -d basic
import scrapy

class $classname(scrapy.Spider):
    name = "$name"
    allowed_domains = ["$domain"]
    start_urls = (
        'http://www.$domain/',
        )

    def parse(self, response):
        pass

scrapy genspider -t basic example example.com
Created spider 'example' using template 'basic' in module:
  mybot.spiders.example

请注意这四种可选的模板

  • crawl

使用spider进行爬取

scrapy crawl myspider
  • check

运行contract检查?

scrapy check -l
first_spider
  * parse
  * parse_item
second_spider
  * parse
  * parse_item

scrapy check
[FAILED] first_spider:parse_item
>>> 'RetailPricex' field is missing

[FAILED] first_spider:parse
>>> Returned 92 requests, expected 0..4
  • list

列出当前项目中所有可用的spider。每行输出一个spider

scrapy list
spider1
spider2
  • edit

使用 EDITOR 中设定的编辑器编辑给定的spider

该命令仅仅是提供一个快捷方式。开发者可以自由选择其他工具或者IDE来编写调试spider。

scrapy edit spider1
  • fetch

使用Scrapy下载器(downloader)下载给定的URL,并将获取到的内容送到标准输出。

该命令以spider下载页面的方式获取页面。例如,如果spider有 USER_AGENT 属性修改了 User Agent,该命令将会使用该属性。 因此,您可以使用该命令来查看spider如何获取某个特定页面。 该命令如果非项目中运行则会使用默认Scrapy downloader设定。

$ scrapy fetch --nolog http://www.example.com/some/page.html
[ ... html content here ... ]

$ scrapy fetch --nolog --headers http://www.example.com/
{'Accept-Ranges': ['bytes'],
 'Age': ['1263   '],
 'Connection': ['close     '],
 'Content-Length': ['596'],
 'Content-Type': ['text/html; charset=UTF-8'],
 'Date': ['Wed, 18 Aug 2010 23:59:46 GMT'],
 'Etag': ['"573c1-254-48c9c87349680"'],
 'Last-Modified': ['Fri, 30 Jul 2010 15:30:18 GMT'],
 'Server': ['Apache/2.2.3 (CentOS)']}
  • view

在浏览器中打开给定的URL,并以Scrapy spider获取到的形式展现。 有些时候spider获取到的页面和普通用户看到的并不相同。 因此该命令可以用来检查spider所获取到的页面,并确认这是您所期望的。

$ scrapy view http://www.example.com/some/page.html
[ ... browser starts ... ]
  • shell

以给定的URL(如果给出)或者空(没有给出URL)启动Scrapy shell。

$ scrapy shell http://www.example.com/some/page.html
[ ... scrapy shell starts ... ]
  • parse

获取给定的URL并使用相应的spider分析处理。如果您提供 --callback 选项,则使用spider的该方法处理,否则使用 parse

支持的选项:

--spider=SPIDER: 跳过自动检测spider并强制使用特定的spider

--a NAME=VALUE: 设置spider的参数(可能被重复)

--callback or -c: spider中用于解析返回(response)的回调函数

--pipelines: 在pipeline中处理item

--rules or -r: 使用 CrawlSpider 规则来发现用来解析返回(response)的回调函数

--noitems: 不显示爬取到的item

--nolinks: 不显示提取到的链接

--nocolour: 避免使用pygments对输出着色

--depth or -d: 指定跟进链接请求的层次数(默认: 1)

--verbose or -v: 显示每个请求的详细信息

$ scrapy parse http://www.example.com/ -c parse_item
[ ... scrapy log lines crawling example.com spider ... ]

>>> STATUS DEPTH LEVEL 1 <<<
# Scraped Items  ------------------------------------------------------------
[{'name': u'Example item',
 'category': u'Furniture',
 'length': u'12 cm'}]

# Requests  -----------------------------------------------------------------
[]
  • runspider

在未创建项目的情况下,运行一个编写在Python文件中的spider。

$ scrapy runspider myspider.py
[ ... spider starts crawling ... ]
  • settings

获取Scrapy的设定 ,在项目中运行时,该命令将会输出项目的设定值,否则输出Scrapy默认设定。

$ scrapy settings --get BOT_NAME
scrapybot
$ scrapy settings --get DOWNLOAD_DELAY
0
Previous2.7 scrapyNext2.9 异步加载

Last updated 6 years ago

Was this helpful?