爬虫(三)之scrapy核心组件

01-核心组件

·五大核心组件的工作流程:

引擎(Scrapy)
 用来处理整个系统的数据流处理, 触发事务(框架核心)

调度器(Scheduler)
 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址

下载器(Downloader)
 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)

爬虫(Spiders)
 爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面

项目管道(Pipeline)
 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

02-post请求

# postPro/postPro/spiders/postDemo.py

# -*- coding: utf-8 -*-
import scrapy
# 需求:百度翻译中指定词条对应的翻译结果进行获取


class PostdemoSpider(scrapy.Spider):
    name = 'postDemo'
    # allowed_domains = ['www.baidu.com']
    start_urls = ['https://fanyi.baidu.com/sug']
    # start_requests 该方法其实是父类中的一个方法:该方法可以对 start_urls 列表中的元素进行get请求的发送
    # 发起post请求的方式:① 将Request 方法中method参数赋值成post(不建议);② FormRequest()可以发起post请求(推荐)
    # 要想发起post请求,一定要对父类中的 start_requests 进行重写。

    def start_requests(self):
        print("执行了start_requests")
        # post的请求参数
        data = {
            'kw': 'dog',
        }
        for url in self.start_urls:
            # formdata: 请求参数对应的字典
            yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse)

    def parse(self, response):
        print(response.text)

03-cookie操作

# doubanPro/doubanPro/spiders/douban.py

# -*- coding: utf-8 -*-
import scrapy


class DoubanSpider(scrapy.Spider):
    name = 'douban'
    # allowed_domains = ['www.baidu.com']
    start_urls = ['https://accounts.douban.com/login']

    def start_requests(self):
        data = {
            "source": "index_nav",
            "redir": "https: // www.douban.com/",
            "form_email": "18844170520@163.com",
            "form_password": "******",
            "login": "登录",
        }
        for url in self.start_urls:
            yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse)

    def parseBySecondPage(self, response):
        # 针对个人主页面数据进行解析操作
        fp = open('./second.html', 'w', encoding='utf-8')
        fp.write(response.text)

    def parse(self, response):
        # 登陆成功后的页面进行存储
        fp = open('./main.html', 'w', encoding='utf-8')
        fp.write(response.text)

        # 获取当前用户的个人主页
        url = 'https://www.douban.com/people/187468735/'
        yield scrapy.Request(url=url, callback=self.parseBySecondPage)

04-代理

下载中间件的作用: 拦截请求, 可以将IP的请求进行更换。

流程:
    1.下载中间件类的自制定
        class MyProxy(object):
            def process_request(self, request, spider):
                # 请求IP的更换
                request.meta['proxy'] = "http://120.76.77.152:9999"  
     2.配置文件中进行下载中间件的开启。
# proxyPro/settings.py
# 打开配置文件中的下载中间件,并配置自定义中间件
# 下载中间件
DOWNLOADER_MIDDLEWARES = {
   # 'proxyPro.middlewares.ProxyproDownloaderMiddleware': 543,
   'proxyPro.middlewares.MyProxy': 543,
}
# proxyPro/middlewares.py

from scrapy import signals


# 自定义一个下载中间件的类,在类中事先process_request(处理中间件拦截到的请求) 方法
class MyProxy(object):
    def process_request(self, request, spider):
        # 请求IP的更换
        request.meta['proxy'] = "http://120.76.77.152:9999"
# proxyPro/proxyDemo.py

# -*- coding: utf-8 -*-
import scrapy


class ProxydemoSpider(scrapy.Spider):
    name = 'proxyDemo'
    # allowed_domains = ['www.baidu.com/s?wd=ip']
    start_urls = ['http://www.baidu.com/s?wd=ip']

    def parse(self, response):
        fp = open('./proxy.html', 'w', encoding='utf-8')
        fp.write(response.text)

05-日志等级

 

# settings.py

# 指定终端输出日志等级
LOG_LEVEL = 'ERROR'

# 把终端输出的日志信息写入到log.txt文件中
LOG_FILE = 'log.txt'

06-请求传参(meta)

解决问题:爬取的数据值不在同一个页面。

需求:将id97电影网站中的电影详情数据进行爬取

# moviePro/spiders/movie.py

# -*- coding: utf-8 -*-
import scrapy
from moviePro.items import MovieproItem


class MovieSpider(scrapy.Spider):
    name = 'movie'
    # allowed_domains = ['www.id97.com']
    start_urls = ['http://www.id97.com/movie']

    # 专门对二级页面进行解析
    def parseBySecondPage(self, response):
        # 导演
        actor = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[1]/td[2]/a/text()').extract_first()
        # 语言
        language = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[6]/td[2]/text()').extract_first()
        # 片长
        longTime = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[8]/td[2]/text()').extract_first()

        # 取出Request 方法的meta 参数传递过来的字典(request.meta)
        item = response.meta['item']
        item['actor'] = actor
        item['language'] = language
        item['longTime'] = longTime

        # 将item提交给管道
        yield item

    def parse(self, response):
        # 名称,类型,导演,语言,片长
        div_list = response.xpath('/html/body/div[1]/div[1]/div[2]/div')

        for div in div_list:
            # 片名
            name = div.xpath('.//div[@class="meta"]/h1/a/text()').extract_first()
            # 类型   如下方法返回的是一个列表,且列表元素为4
            kind = div.xpath('.//div[@class="otherinfo"]//text()').extract()
            # 转化为字符串
            kind = "".join(kind)
            # 详情页的url
            url = div.xpath('.//div[@class="meta"]/h1/a/@href').extract_first()

            # 创建item对象
            item = MovieproItem()
            item['name'] = name
            item['kind'] = kind

            # 问题:如何将剩下的电影详情数据存储到item对象(meta参数)

            # 需要对url发起请求,获取页面数据,进行指定的数据解析, meta会将字典传递给回调函数
            # meta 只可以赋值为 一个字典
            yield scrapy.Request(url=url, callback=self.parseBySecondPage, meta={'item': item})

07-CrawlSpider

# 创建项目文件

scrapy startproject crawlSpiderPro

scrapy genspider -t crawl chouti https://dig.chouti.com
# spiders/chouti.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
'''
LinkExtractor : 链接提取器对应的类
    LinkExtractor(allow=r'Items/') 实例化
        作用:用来提取指定的url,allow参数:赋值一个正则表达式,就可以根据正则在页面中提取指定的url
        提取到的链接url 会全部交给 规则解析器Rule,
Rule : 规则解析器对应的类
    Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
        Rule 接受了 LinkExtractor 发送的链接url后,就会对链接发起请求,获取url对应的页面内容,
        然后就会根据 指定的规则 对页面内容进行指定的页面解析,

callback:指定了一个解析规则 parse_item(方法/函数)
follow:是否将 链接提取器 继续作用到 链接提取器提取出的链接 所表示的页面数据中
'''


class ChoutiSpider(CrawlSpider):
    name = 'chouti'
    # allowed_domains = ['https://dig.chouti.com']
    start_urls = ['https://dig.chouti.com/']

    rules = (
        # 实例化了一个规则解析器对象
        Rule(LinkExtractor(allow=r'/all/hot/recent/d+'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        print(response)
        # 再进行数据解析.........

        # i = {}
        # # i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()
        # # i['name'] = response.xpath('//div[@id="name"]').extract()
        # # i['description'] = response.xpath('//div[@id="description"]').extract()
        # return i

 

原文地址:https://www.cnblogs.com/pgxpython/p/10041626.html