Scrapy爬虫----(二)项目实战(下)

这篇文章主要记录和讲解的是爬虫模块中parse方法的使用,构建Item pipeline,定制自己的的Item pipeline、Settings的设置以及代码的实现。

数据提取(续):

Spider类整体上来看是定义了爬虫爬取的动作(例如页面是否跟进)和分析网页的结构以及从网页的内容中提取结构化的数据item

整体的循环流程:
A.以入口的URL初始化Request,并设置回调函数。此Request下载完毕后返回Response,并作为参数返回给回调函数。spider中初始的Request是通过调用start_requests()方法获取,start_requests()读取start_urls中的URL,并以parse为回调函数生成Request。

B.在回调函数中,分析参数Response,返回Item对象、dict、Request或者一个包括三者的可迭代容器。

C.在回调函数内,可以使用选择器(selector)或者其他第三方解释器来分析response,(这里可以为通过requests解析下载的网页内容),并根据分析的数据生成item。

D.通过使用yield而非return返回数据类型,可以将parse打造一个生成器,scrapy会逐一获取parse()方法中生成的结果,并判断生成的结果类型加以处理。

E.处理的过程如下:

  1. 如果是获取的是Request对象,会经过scrapy处理,下载响应的内容,并调用设置的回调函数,可以使parse()后者其他函数。如果是item类型则使用pipelines处理,其他类型则返回错误信息。
  2. parse()方法作为回调函数(通过callback来调用响应的方法)赋值给了Request,指定parse()方法来处理这些请求 scrapy.Request(url, callback=self.parse)。Request对象经过调度,执行生成 scrapy.http.response()的响应对象(实际上是对网页的下载),并将返回的Response参数送回给parse()方法,直到调度器中没有Request(递归的思路);
  3. 在此过程之中, scrapy取到第一部分的Request不会立马就去发送这个Request,只是把这个Request放到队列里,然后接着从生成器里获取;
  4. 取尽第一部分的Request,然后再获取第二部分的item,取到item后,就会放到对应的pipelines里处理;
  5. 当所有的返回对象取尽之后,parse()工作结束,引擎再根据Request队列和pipelines中的内容去执行相应的操作;程序在取得各个页面的items前,会先处理完之前所有的Request队列里的请求,然后再提取items。
  6. 以上的全部过程由Scrapy引擎和调度器负责到底。

scrapy整体架构图示:
scrapy整体架构图

再回头看scrapy运行的流程就会比较清晰了

  1. 首先是获取队列中第一个需要爬取的URL,即是start_urls,通过调度器Schedule和Request进行调度。目的事下载由初始的网页内容。
  2. 引擎向调度器请求爬取的URL,调度器将该URL返回给引擎。Scrapy Engine会使用Downloader Middlewares 下载中间件对网页进行下载。
  3. 一旦网页下载完毕,下载器将生成这个网页的Responses,并将其通过Downloader Middlewares 下载中间件发送给引擎。
  4. 引擎将从下载器中接收到的Response通过Spider Middlewares 返回给Spiders模块中的parse()方法进行处理。
  5. Spiders中回调函数(不仅仅有parse()也可是自己编写的回调函数)处理响应的Response,以yield返回爬取到的(跟进的)Request和item给引擎。
  6. 引擎将爬取到的Item交给Item Pipelines,进行数据的后续处理。
  7. 引擎将爬取到的Request交给调度器,重复开始新的调度过程。
  8. 当调度器中没有可调度的Request时,引擎关闭。

接下来我们可以实现parse方法

#!/usr/bin/python
# coding:utf-8
import scrapy
from ..items import Testdemo001Item

class YtlSpider(scrapy.Spider):
    # 爬虫的唯一名字,不能为不同的spider设置相同的名字
    name = 'ytl'
    # 爬虫允许爬取URL的域名范围,这个爬虫允许的爬取的范围为yetianlian.com
    allowed_domains = ['yetianlian.com']
    # start_urls 是spider在启动时进行爬取的入口的URL列表。因此,第一个被获取的URL也是其中之一
    # 后续的URL则会从初始的URL的响应中主动提取
    start_urls = ['http://yetianlian.com']

    # parse() 函数,是spider的一个方法。被调用时,根据初始的URL响应后的返回的Response对象
    # 将会作为唯一的参数传递给该方法。该方法有三个功能
    # (1.解析返回的数据(response data) 2.提取数据(生成item) 3.生成需要进一步处理的URL的Request对象)
    def parse(self, response):
        # 获取文章的标题
        P_title = response.xpath('//*[@id="post-1135"]/div/h3/text()').extract()[0]
        # C_titles = response.xpath('//*[@id="post-1135"]//h2/text()').extract()[1:]
        # 获取文章章节跟进的url
        urls = response.xpath('//*[@id="post-1135"]//ul/li/a/@href').extract()[8:]
        #获取文章章节标题
        A_titles = response.xpath('//*[@id="post-1135"]//ul/li/a/text()').extract()[8:]

        for i in range(len(urls)):
            # # 初始化item的两种方法
            # item = Testdemo001Item(p_title = P_title,c_title = C_title,url = url,a_title = A_title)
            # yield item
            item = Testdemo001Item()
            item['p_title'] = P_title
            try:
                item['chapternum'] = A_titles[i].split(' ')[0]
                item['chaptertitle'] = A_titles[i].split(' ')[1]
                item['chapterurl'] = urls[i]

                request = scrapy.Request(urls[i], callback=self.body_parse)
                # meta属性的说明:作用是传递信息给下一个函数,跟随请求并包含元数据的字典。也可以往字典中添加字段
                request.meta['item'] = item
                yield request

            except Exception,e:
                print 'exception',e
                continue

    def body_parse(self,response):

        item = response.meta['item']
        item['chaptercontent'] = response.xpath('//*[@id="post-3"]//p/text()').extract()

        yield item
        # pass是空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句
        pass

程序中使用callback调用body_parse方法,实现对每一个章节内容的获取。(scrapy.Request(urls[i], callback=self.body_parse))
这个程序里面没有涉及到翻页的问题,关于翻页的问题,后续的文章中会有细致说明。

3.4 Item Pipelines.py


首先应该明白Item Pipeline的作用:它是为了将爬虫之前爬取到的数据Item进行持久化的存储。
两大步骤:a.定制Item Pipeline. b.Settings.py中激活Item Pipieline
四个典型的应用:
a.清理HTML数据
b.验证爬取数据的合法性,检查Item是否包含有某些字段
c.查重并丢弃
d.将爬取到的结果保存到文件或者数据库中

每一个Item Pipeline组件是一个独立的Python类,必须实现process_item的方法,方法的原型是:process_item(self, item, spider)
该方法在Item数据处理的时候都会被Item Pipeline调用,该方法必须返回一个item或者是抛出的异常
参数item:表示被爬取的Item对象
参数spider:表示爬取该Item的spider

第一步:定制Item Pipeline
pipelines.py 代码

import codecs
import os
import json
import sqlite3
from scrapy.exceptions import DropItem

from . import settings


class Testdemo001Pipeline(object):
    '''

    '''
    def process_item(self, item, spider):
        # 创建文件保存路径
        dir_path = '%s%s'%(settings.FILE_STORE,item['p_title'] + '---' + item['chapternum'])
        print 'dir_path',dir_path
        # 如果文件保存路径不存在,创建一个新的文件路径
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        # 在dir_path下创建文件 ‘ + '\\' ’
        file_path = '%s%s' %(dir_path + '\\',item['chapternum'] + ' ' + item['chaptertitle'] + '.txt')

        with codecs.open(file_path,'w',encoding='utf-8') as file_writer:
            file_writer.writelines(item['chaptercontent'])
            file_writer.write('\r\n')
        file_writer.close()

        return item

第二步:激活Item Pipeline

需要在settings.py文件中添加下列代码:

ITEM_PIPELINES = {
    'TestDemo001.pipelines.Testdemo001Pipeline': 300,
}

其中TestDemo001.pipelines表示的是处理Item使用pipelines文件路径(从“包含Python项目模块的文件夹”开始的路径)
其中Testdemo001Pipeline表示的是pipelines文件中调用的类名
300表示的是该Pipeline调用的先后顺序(这些数字的定义范围是:0~1000)

另外需要设置FILE_STORE

定制Item Pipeline中使用到了settings.py中设置的文件路径,所以settings.py中应设置FILE_STORE

# 创建文件保存路径
        dir_path = '%s%s'%(settings.FILE_STORE,item['p_title'] + '---' + item['chapternum']
FILE_STORE = 'D:\\File\\Download\\ytl\\'

另外还有其他的数据存储一些内容,后续的文章中会详细介绍。有关于scrapy内置数据的存储,scrapy内置的图片和文件下载方式,个人定制图片和文件下载方式,常用的文件保存和图片保存方式以及利用数据库存储数据。

3.5 settings.py


在Item Pipeline中我们已经对settings.py文件进行修改,在settings.py中,我后续还要加入User-Agent,Downloader Middlewares,Spider Middlewares,IP_Proxy代理资源池等内容的设置。

settings.py代码:

#!/usr/bin/python
# coding:utf-8

BOT_NAME = 'TestDemo001'

SPIDER_MODULES = ['TestDemo001.spiders']
NEWSPIDER_MODULE = 'TestDemo001.spiders'

FILE_STORE = 'D:\\File\\Download\\ytl\\'


# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'TestDemo001 (+http://www.yourdomain.com)'

# Obey robots.txt rules
# 有些网站需要将该功能关闭 即该值设置为false
ROBOTSTXT_OBEY = True

ITEM_PIPELINES = {
    'TestDemo001.pipelines.Testdemo001Pipeline': 300,
    # 'TestDemo001.database.mypipeline.mypipeline':135,
}

3.6 运行spider crawl


这里提供两个方法来运行spider

a.打开cmd命令窗口,cd到项目文件夹下,运行scrapy crawl ytl命令
b.在项目文件夹下建立一个XXX.py,在文件中写入调用运行爬虫的命令代码,在IDE下运行这个XXX.py文件即可

#!/usr/bin/python
# coding:utf-8

from scrapy import cmdline

cmdline.execute("scrapy crawl ytl".split())

# cmdline.execute("scrapy crawl ytl -o hysxm.csv".split())

结语:


两篇文章讲述了整体spider爬虫爬取数据的流程,这里爬取的是一个简单的教程,算是抛砖引玉。
如果在阅读的过程中如果遇到有问题请指出,若对文章中的内容如有不同的见解,欢迎一起学习讨论。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值