scrapy学习(一)

1.Scrapy架构图(绿线是数据流向)

 

Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。

Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。

Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,

Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器),

Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方.

Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。

Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)

 

2.制作Scrapy Spider的步骤

  (1)新建项目(scrapy startproject xxx):新建一个新的爬虫项目

  (2)明确目标(编写items.py,其中的字段为要爬取的关键信息):明确想要抓取的目标

  (3)制作爬虫(编辑spiders/xxx_spider.py):制作爬虫,开始爬取网页

  (4)存贮内容(编辑pilelines.py):设计管道,存储爬取的内容。

 

项目一:百度翻译

spider组件代码:

import scrapy
import json

class TranslationsSpider(scrapy.Spider):
    name = 'translations'
    # allowed_domains = ['translations.com']
    start_urls = ['https://fanyi.baidu.com/sug']

    # scrapy默认发起一个get请求
    # 思考:scrapy如何发起一个post请求
    # 需要重写父类的start_requests方法
    # start_requests()方法永远是scrapy的初始请求的发送者
    # 之所以,start_urls也能够成为初始请求的发送者,是因为
    # 父类的start_requests()方法就是从start_urls中取出URL发起get请求的
    # 所以,如果需要第一步就发起post请求,必须重写父类的start_requests()


    # 如果发起的post请求,使用FormRequest方法
    def start_requests(self):
        data = {'kw': 'as'}
        # callback: 指定该请求返回的Response,由那个函数来处理。
        # formdata是post请求发送的数据
        # yield 的作用就是把一个函数变成一个生成器(generator),与return区别,不会结束程序
        # yield 来发起一个请求,并通过 callback 参数为这个请求添加回调函数,在请求完成之后会将响应作为参数传递给回调函数
        yield scrapy.FormRequest(url=self.start_urls[0],formdata=data,callback=self.parse)

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

 项目二:利用Scrapy自定义文件和图片下载类完成文件和图片的下载

-- FilesPipeline

--ImagesPipeline

(1)下载文件地址:https://matplotlib.org/2.0.2/examples/index.html

其相关配置:

ITEM_PIPELINES = {
    'download_files.pipelines.DownloadFilesPipeline': 300,
    'download_files.pipelines.DownloadImagesPipeline': 300,
    # 'scrapy.pipelines.files.FilesPipeline': 300,
}

# 存放文件的路径
FILES_STORE = 'files'
# 存放图片的路径
IMAGES_STORE = 'images'

 

files的spider组件代码:

import scrapy
from ..items import DownloadFilesItem

class FilesSpider(scrapy.Spider):
    name = 'files'
    # allowed_domains = ['files.com']
    start_urls = ['https://matplotlib.org/2.0.2/examples/index.html']

    def parse(self, response):
        li_list = response.xpath('//li[@class="toctree-l2"]')
        for li in li_list:
            href = li.xpath('./a/@href').get()
            # urljoin(相对路径)   自动将不完整链接拼接成完整的链接
            full_href = response.urljoin(href)
            # 发起二次请求
            yield scrapy.Request(url=full_href, callback=self.downloads)

    def downloads(self, response):
        href = response.xpath('//div[@class="section"]/p[1]/a[1]/@href').get()
        # 将相对路径变为绝对路径
        full_href = response.urljoin(href)
        # 实例化对象
        item = DownloadFilesItem()
        # 注意:file_urls值必须是一个列表
        item['file_urls'] = [full_href]

        yield item

 

images的spider组件代码

import scrapy
import json
from ..items import DownloadImagesItem

class ImageSpider(scrapy.Spider):

    name = 'images'
    start_urls = ['https://image.so.com/zjl?ch=beauty&sn=60']

    def parse(self, response, **kwargs):
        image_data = json.loads(response.text)
        image_list = image_data['list']
        for image in image_list:
            item = DownloadImagesItem()
            title = image['title']
            image_urls = image['qhimg_url']

            item['image_name']=title
            item['image_urls']=[image_urls] # 每次传入一个url
            yield item # 返回值时,每个item都是一个title、一个urls这样的好处是不用考虑title和url对应的问题,方便pipelines保存

 

items文件代码:

import scrapy

class DownloadFilesItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    # 定义文件的url
    # file_urls变量名不能改动
    file_urls = scrapy.Field()


class DownloadImagesItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    # 定义图片的url,固定
    image_urls = scrapy.Field()

    # 定义图片的名称
    image_name = scrapy.Field()

 

pipelines文件代码:

from scrapy.pipelines.images import ImagesPipeline
from scrapy.pipelines.files import FilesPipeline
import scrapy
class DownloadFilesPipeline(FilesPipeline):
    # 重写父类的文件保存的方法
    def file_path(self, request, response=None, info=None, *, item=None):
        # 获取文件名
        file_name = request.url.split('/')[-1]
        return f'full/{file_name}'

    # def process_item(self, item, spider):
    #     return item

class DownloadImagesPipeline(ImagesPipeline):

    # def get_media_requests(self, item, info):
    #     for image_url in item['image_urls']:
    #         yield scrapy.Request(url=image_url)

    def file_path(self, request, response=None, info=None, *, item=None):
        # image_name = item['image_name'][item['image_urls'].index(request.url)]
        image_name = item['image_name']
        return f"360/{image_name}.jpg"

 scrapy中使用selenium

from selenium import webdriver
from scrapy.http import HtmlResponse

class DbydDownloaderMiddleware(object):
    # 定义初始化函数
    def __init__(self):
        # 调用浏览器
        self.driver = webdriver.Chrome(executable_path=r'D:\chrome\chromedriver.exe')
        pass

    def process_request(self, request, spider):
        if 'dcm' in request.url:
            # 最大化浏览器
            self.driver.maximize_window()

            # 发起请求
            self.driver.get(url=request.url)
            # 获取内容
            content = self.driver.page_source

            return HtmlResponse(body=content,encoding='utf-8',url=request.url)
        else:
            return None

扩展: 将数据保存到Excel中(示例)

from openpyxl import Workbook

# 1.实力化对象
wb = Workbook()

# 2.激活工作表
ws = wb.active

# 3.填写表头
ws.append(['阅读数','评论数','标题','作者','时间'])

# 插入内容lst为内容列表
ws.append(lst)
 
# 保存
wb.save('股吧.xlsx')

详细操作:   

https://vlambda.com/wz_yL8VKk2AcVl.html

https://blog.csdn.net/weixin_41546513/article/details/109555832

posted @ 2021-07-11 23:57  千叶千影  阅读(82)  评论(0编辑  收藏  举报