【爬虫】第七部分 scrapy

news2024/12/26 22:12:57

【爬虫】第七部分 scrapy


文章目录

  • 【爬虫】第七部分 scrapy
  • 7. scrapy
    • 7.1 基本使用
    • 7.2 项目的文件结构
    • 7.3 response的方法和属性
    • 7.4 小案例
    • 7.5 scrapy 工作原理
    • 7.6 管道的使用
    • 7.7 多管道下载
    • 7.8 下载分页类型和get请求的使用
    • 7.9 下载多层级类型
    • 7.10 post请求的使用
  • 总结


7. scrapy

7.1 基本使用

  1. pip install scrapy 安装

  2. 在终端运行以下代码: scrapy startproject 项目名字 创建爬虫项目(名字不要中文)

  3. cd 进入到 spiders,再运行下面创建爬虫文件的指令

在这里插入图片描述

scrapy genspider 爬虫文件名 要爬取的网页 创建爬虫文件(名字不要中文)

ex: scrapy genspider xxx www.xxx.com

这个时候我们就会看到spiders下面生成了xxx.py文件
在这里插入图片描述

  1. 运行爬虫文件 scrapy crawl 爬虫文件名字 ,注意运行之前到settings中将robot协议改了,才可以爬取

在这里插入图片描述


7.2 项目的文件结构

scrapy 项目的文件结构
    - 项目名
        - 项目名
           - spiders
                init
                自定义的爬虫文件
           - init
           - items  定义数据结构的地方
           - middleware 中间件  代理
           - pipelines  管道 用来处理下载下来的数据
           - settings 配置文件 robots协议 us定义等

7.3 response的方法和属性

extract(): 这个方法返回的是一个数组list里面包含了多个string,如果只有一个string,则返回[‘ABC’]这样的形式。

extract_first():这个方法返回的是一个string字符串是list数组里面的第一个字符串

import scrapy

class BaiduSpider(scrapy.Spider):
    # 爬虫文件的名字,用于运行爬虫的时候使用
    name = 'baidx'
    # 允许访问的域名
    allowed_domains = ['www.baidx.com']
    # 起始的url地址,指的是第一次要访问的域名
    # 这里需要注意一下,一般情况下将start_urls中 / 给去掉,不然容易出现一些问题
    start_urls = ['http://www.baidx.com']

    # 该方法中的response相当于 response = requests.get()
    def parse(self, response):
        res1 = response.text  # 拿到的是字符串,网页源码
        res2 = response.body  # 拿到的是二进制数据
        print("===========================================================")
        # 可以直接使用xpath的方法
        content = response.xpath('//input[@id="su"]/@value')
        # 使用extract()方法进行提取
        print(content.extract())

7.4 小案例

爬取汽车信息

import scrapy


class CarSpider(scrapy.Spider):
    name = 'car'
    allowed_domains = ['https://xxx.autohome.com.cn/price/brand-15.html']
    start_urls = ['https://xxx.autohome.com.cn/price/brand-15.html']

    def parse(self, response):
        print("===========================")
        name_list = response.xpath('//div[@class="main-title"]/a/text()')
        price_list = response.xpath('//div[@class="main-lever-right"]/div/span/span/text()')
        for i in range(len(name_list)):
            res = name_list[i].extract() + '--->  ' + price_list[i].extract()
            print(res)


7.5 scrapy 工作原理

在这里插入图片描述

根据上述的流程图,绘制下图:

在这里插入图片描述

  1. 首先将spiders向引擎提供url
  2. 引擎将要爬取的url给调度器
  3. 调度器会将url生成请求对象放入到指定的队列中,队列中出队一个请求给引擎
  4. 引擎将请求件给下载器进行处理
  5. 下载器发送请求获取互联网数据
  6. 下载回来
  7. 下载器将数据返回给引擎
  8. 引擎将数据交给spiders,通过xpath解析数据
  9. 解析后的 数据 或者 url 交给引擎
  10. 引擎进行判断,如果是url则交给调度器,进行上述操作,如果是数据就交给管道保存下来

7.6 管道的使用

  1. 创建项目 : scrapy startproject dangdang

  2. 进入到spiders去创建爬虫文件 : scrapy genspider dang_data https://book.dangdang.com/01.03.htm?ref=book-01-A

  3. 编写创建出来的爬虫文件

    import scrapy
    # 导入定义数据结构
    from dangdang.items import DangdangItem
    
    class DangDataSpider(scrapy.Spider):
        name = 'dang_data'
        allowed_domains = ['https://book.dangdang.com/01.03.htm?ref=book-01-A']
        start_urls = ['https://book.dangdang.com/01.03.htm?ref=book-01-A']
    
        def parse(self, response):
            # src   //ul[@class="list_aa"]//li[@type="rollitem"]//li/a/img/@src
            # bookname //ul[@class="list_aa"]//li[@type="rollitem"]//li/p[@class="name"]/a/text()
            # author  //ul[@class="list_aa"]//li[@type="rollitem"]//li/p[@class="author"]/text()
            base = response.xpath('//ul[@class="list_aa"]//li[@type="rollitem"]//li')
            # 只要是selector对象就可以继续调用xpath
            for item in base:
                # 在这里需要注意加上 .  ,表示当前
                src = item.xpath('./a/img/@src').extract_first()
                bookname = item.xpath('./p[@class="name"]/a/text()').extract_first()
                author = item.xpath('./p[@class="author"]/text()').extract_first()
                # book实际上就是通过items整理好的对象,将该对象交给pipelines下载
                book = DangdangItem(src=src, bookname=bookname, author=author)
                # 使用yield 把对象交给pipelines
                yield book
    
  4. 在items文件中定义数据结构

    import scrapy
    
    class DangdangItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        # 在这里需要去定义你要下载的数据有哪些
        # 图片
        src = scrapy.Field()
        # 书名
        bookname = scrapy.Field()
        # 作者
        author = scrapy.Field()
    
  5. settings去开启管道

在这里插入图片描述

  1. 在pipelines文件中编写

    # 在使用管道前,需要去settings下开启管道
    class DangdangPipeline:
        # 这是一个在爬虫文件开始之前就执行的一个方法
        def open_spider(self, spider):
            self.f = open('book_msg.json', 'w', encoding='utf-8')
    
        def process_item(self, item, spider):
            # 这里的item就是yield返回过来的对象
            # write方法必须接受一个字符串而不能是其他的对象,需要强转
            self.f.write(str(item))
            # 注意一定要返回
            return item
    
        # 在爬虫文件执行完之后执行的一个方法:
        def close_spider(self, spider):
            self.f.close()
    
    

7.7 多管道下载

  1. 在pipelines原先的基础上模仿写

    # 在使用管道前,需要去settings下开启管道
    class DangdangPipeline:
        # 这是一个在爬虫文件开始之前就执行的一个方法
        def open_spider(self, spider):
            self.f = open('book_msg.json', 'w', encoding='utf-8')
    
        def process_item(self, item, spider):
            # 这里的item就是yield返回过来的对象
            # write方法必须接受一个字符串而不能是其他的对象,需要强转
            self.f.write(str(item))
            return item
    
        # 在爬虫文件执行完之后执行的一个方法:
        def close_spider(self, spider):
            self.f.close()
    
    
    import urllib.request
    
    
    # 开启多管道下载
    class DangdangDownload:
        def process_item(self, item, spider):
            url = 'https:' + item.get('src')
            filename = './books/' + item.get('bookname') + '.png'
            urllib.request.urlretrieve(url=url, filename=filename)
            return item
    
    
  2. 到settings文件中去添加新的管道,一样模仿这写

    # 开启管道,管道是有优先级的,优先级的范围是1-1000,值越小优先级越高
    ITEM_PIPELINES = {
        'dangdang.pipelines.DangdangPipeline': 300,
        # 开启多管道
        'dangdang.pipelines.DangdangDownload': 301
    }
    

7.8 下载分页类型和get请求的使用

创建出来的爬虫文件

import scrapy
import json
from pptmodel.items import PptmodelItem


class PptDemoSpider(scrapy.Spider):
    name = 'ppt_demo'
    # 对于下载分页这种类型,allowed_domains需要写成域名
    allowed_domains = ['theuser.zhuisoft.com']
    start_urls = [
        'http://theuser.zhuisoft.com/template/ajax_web/data_list?class=&type_id=0&order_by=0&title=&format=&page=0&num=40']

    def parse(self, response):
        res = response.text
        data = json.loads(res).get('data')
        for item in data:
            title = item.get('title')
            img = item.get('cover_img')
            ppt = PptmodelItem(title=title, img=img)
            yield ppt
        
        # 下载3页
        for i in range(1, 3):
            url = f'http://theuser.zhuisoft.com/template/ajax_web/data_list?class=&type_id=0&order_by=0&title=&format=&page={i}&num=40'
            # scrapy.Request 就是scrapy的get请求,注意这里调用函数不能写括号
            yield scrapy.Request(url=url, callback=self.parse)


7.9 下载多层级类型

创建出来的爬虫文件

import scrapy
from movie_demo.items import MovieDemoItem


class MvSpider(scrapy.Spider):
    name = 'mv'
    allowed_domains = ['0dytt.com']
    start_urls = ['https://0dytt.com/frim/1.html']

    """
        案例描述: 
            1. 需要在首页拿到电影名和跳转的链接
            2. 请求跳转的链接,xpath解析,拿到电影海报
    """

    def parse(self, response):
        # href  //div[@class="hy-video-list"]//li/a/@href
        # title //div[@class="hy-video-list"]//li/a/@title

        base = response.xpath('//div[@class="hy-video-list"]//li/a')
        for i in base:
            href = 'https://0dytt.com' + i.xpath('./@href').extract_first()
            film_name = i.xpath('./@title').extract_first()

            # 这个时候去请求拿到的新链接
            # 在这里使用meta参数用来将电影名传入parse_picture
            yield scrapy.Request(url=href, callback=self.parse_picture, meta={"film_name": film_name})

    # 因为页面结构的不同不能像上一个案例那样调用自己,所以需要创建一个新的函数
    def parse_picture(self, response):
        all_actor = ''
        style = response.xpath('//div[@class="hy-video-details clearfix"]//a/@style').extract_first()
        lead_actor = response.xpath('//div[@class="hy-video-details clearfix"]//ul/li[1]//a/text()').extract()
        for actor in lead_actor:
            all_actor = all_actor + actor
        film_name = response.meta['film_name']
        start = style.find('(')
        end = style.find(')')
        src = 'http' + style[start + 6:end]

        info = MovieDemoItem(src=src, film_name=film_name, lead_actor=all_actor)
        yield info

pipelines文件

class MovieDemoPipeline:
    def open_spider(self, spider):
        self.f = open('movie.json', 'w', encoding='utf-8')

    def process_item(self, item, spider):
        self.f.write(str(item) + ',')
        return item

    def end_spider(self, spider):
        self.f.close()


import urllib.request
import random


class MoviePicture:
    def process_item(self, item, spider):
        src = item.get('src')
        filename = 'posters/' + item.get('film_name') + '.jpg'
        # 在这里遇到了防爬,所以需要进行伪装
        ua_list = ['Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0',
                   'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
                   'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62',
                   'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0',
                   'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X MetaSr 1.0'
                   ]
        # 创建opener对象
        opener = urllib.request.build_opener()
        # 给opener添加请求头
        opener.addheaders = [('User-Agent', random.choice(ua_list))]
        # 将opener设置为全局安装
        urllib.request.install_opener(opener)
        urllib.request.urlretrieve(url=src, filename=filename)
        return item


7.10 post请求的使用

import scrapy
import json


class TranslateSpider(scrapy.Spider):
    name = 'translate'
    allowed_domains = ['fanyi.baidu.com']
    # start_urls = ['http://fanyi.baidu.com/sug']
    # def parse(self, response):
    #     pass
    """
        这里的写法,和我们使用get请求就不一样了
        因为post请求需要携带参数,而start_urls第一次请求没有办法携带,
        导致parse函数接收不到response,所以注释掉
    """

    def start_requests(self):
        url = 'http://fanyi.baidu.com/sug'
        data = {
            "kw": "hello"
        }
        # scrapy.FormRequest()就是post请求
        yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse_1)

    def parse_1(self, response):
        res = response.text
        print(json.loads(res))


总结

以上就是今天要讲的内容,希望对大家有所帮助!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164130.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

清华大学出版——C语言从入门到精通(第4版)

《C语言从入门到精通(第4版)》是清华大学出版社出版的图书,该书从初学者的角度出发,以通俗易懂的语言,丰富多彩的实例,详细介绍了使用C语言进行程序开发需要掌握的各方面知识。《C语言从入门到精通&#xf…

YOLO v8详解

回顾一下YOLOv5 Backbone:CSPDarkNet结构,主要结构思想的体现在C3模块,这里也是梯度分流的主要思想所在的地方;PAN-FPN:双流的FPN,但是量化还是有些需要图优化才可以达到最优的性能,比如cat前后…

VSCode 配置Go环境,弹出警告“golps”等插件要求下载但下载时超时、失去连接等 解决方案

1. 背景: 下载完GO环境和VSCode的GO配套插件后,试图运行hello world程序,此时VSCode弹出警告: 提示有几个go的工具没有下载,于是我点击install 下载: 》下载时报错,一般是出现超时timeout错误…

57 mac 中 SIGINFO 信号, jdk8 支持, 但是 jdk9 不支持?

前言 问题来自于文章 shell脚本 后台启动 程序1 “tail -f log“, ctrl c 导致程序1中断 中的测试用例 Test07Signal2ParentProcess, 可以看到 我当时标记了一个 "todo, not work in hostpostVM9" 然后 问题是这样的, 我同一台机器, 然后 jdk8 带上 SIGINFO 去执行…

【已解决】右键以某应用打开xx文件时,没有“默认”选项怎么办

问题解决方案简单来说详细操作解释问题 右键以某应用打开xx文件时,没有“默认”选项 解决方案 简单来说 在注册表:计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\找到要打开的文件后缀名,删除…

mybatis plus基本使用初体验01

我们都知道MyBatis是目前比较常用的持久层框架;这个框架的使用也是很简单的,我们在使用的时候,只需要关注mapper的接口层和对应的xml文件即可。 但是MyBatis作为一个半自动框架,是需要我们自己手动编写sql语句的,对于…

Linux系统软件安装

在Linux上部署各类软件MySQL数据库管理系统安装部署简介注意MySQL5.7版本在CentOS系统安装安装配置MySQL8.0版本在CentOS系统安装安装配置MySQL5.7版本在Ubuntu(WSL环境)系统安装安装MySQL8.0版本在Ubuntu(WSL环境)系统安装安装To…

Web服务统一身份认证协议设计与实现

单点登录(SSO)是目前比较流行的企业业务整合的解决方案之一,它的机制是在企业网络用户访问企业网站时作一次身份认证,随后就可以对所有被授权的网络资源进行无缝的访问,而不需要多次输入自己的认证信息.Web服务具有松散耦合、语言中立、平台无关性、开放性的特性,通过对集中单点…

Qt扫盲-Qt 属性系统记录

Qt 属性系统记录一、概述二、属性声明三、通过元对象系统读写属性四、简单例子五、动态属性六、对一个类添加额外的属性一、概述 Qt 提供了一个复杂的属性系统,类似于一些编译器供应商提供的系统。然而,作为一个独立于编译器和平台的库,Qt并…

Java基础07——集合

Java基础07——集合一、集合和数组的对比二、ArrayList成员方法三、集合练习1. 添加数字并遍历2. 添加学生对象并遍历学生类测试类输出结果3. 添加用户对象并判断是否存在用户类测试类输出结果4. 添加手机对象并返回要求的数据(返回多个数据)手机类测试类…

【算法】Day06

努力经营当下,直至未来明朗! 文章目录1. BST二叉搜索树的后序遍历序列2. 二叉树中和为某一值的路径(二)[回溯法]3. 字符串的排列 [全排列问题]4. 最小的K个数 [topK问题]普通小孩也要热爱生活! 1. BST二叉搜索树的后序…

IF:6+ 综合分析揭示了一种炎症性癌症相关的成纤维细胞亚型在预测膀胱癌患者的预后和免疫治疗反应方面具有重要意义...

桓峰基因的教程不但教您怎么使用,还会定期分析一些相关的文章,学会教程只是基础,但是如果把分析结果整合到文章里面才是目的,觉得我们这些教程还不错,并且您按照我们的教程分析出来不错的结果发了文章记得告知我们&…

Linux 中断子系统(七):注册中断

Linux 注册中断的 API request_irq():不使用中断线程化request_threaded_irq():使用中断线程化中断线程化 为什么需要将中断下半部处理线程化,原因如下: 中断具有最高优先级,有中断发生时,会抢占进程,导致实时任务不能及时处理。中断上下文总是可以抢占进程上下文,这…

【PyTorch】教程:学习基础知识-(3) Datasets-DataLoader

Dataset & DataLoader PyTorch 提供了两个数据处理的基本方法:torch.utils.data.DataLoader torch.utils.data.Dataset 允许使用预加载的数据集以及自己的数据。 Dataset 存储样本及其对应的标签, DataLoader 在 Dataset 基础上封装了一个可迭代的对…

Python文本颜色设置

Python文本颜色设置实现过程:书写格式:数值表示的参数含义:常见开头格式:实例:实现过程: 终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关。 转义序…

Acwing4699. 如此编码

某次测验后,顿顿老师在黑板上留下了一串数字 23333 便飘然而去。 凝望着这个神秘数字,小 P 同学不禁陷入了沉思…… 已知某次测验包含 nn 道单项选择题,其中第 i 题(1≤i≤n)有 ai 个选项,正确选项为 bi&…

CAS And Atomic

CAS(Compare And Swap 比较并交换),通常指的是这样一种原子操作:针对一个变量,首先比较它的内存值与某个期望值是否相同,如果相同,就给它赋一个新值,底层是能保证cas是原子性的CAS的应用 在Java 中,CAS 操作…

Android开发-AS学习(三)(布局)

相关文章链接:Android开发-AS学习(一)(控件)Android开发-AS学习(二)(控件)Android开发应用案例——简易计算器(附完整源码)二、布局2.1 Linearyout常见属性说…

测试NGINX和uwsgi.ini设置

1.uwsgi修改测试 将服务器升级到16核16G配置后,我将uwsgi.ini中的部分参数调整如下: processes 32 threads 16 结果是导致内存暴满,然后直接服务器都无法连接,导致服务器卡死。之前有博客说processes处理器*2,结果…

【阶段三】Python机器学习26篇:机器学习项目实战:LightGBM回归模型

本篇的思维导图: 项目实战(LightGBM回归模型) 项目背景 为促进产品的销售,厂商经常会通过多个渠道投放广告。本案例将根据某公司在电视、广播和报纸上的广告投放数据预测广告收益,作为公司制定广告策略的重要参考依据。 本项目应用LightGBM回归算法进行项目实战,整…