当前位置: 首页 > news >正文

不会JS逆向也能高效结合Scrapy与Selenium实现爬虫抓取

1. 创建基础的scrapy项目

1.1 基础项目

  1. 在pycharm中安装scrapy框架

pip install scrapy

  1. 创建项目

scrapy startproject 项目名称

我们现在可以看到整体文件的目录:

firstBlood
├── firstBlood # 项目跟目录
│ ├── init.py
│ ├── items.py # 封装数据的格式
│ ├── middlewares.py # 所有中间件
│ ├── pipelines.py # 所有的管道
│ ├── settings.py # 爬虫配置信息
│ └── spiders # 爬虫文件夹, 稍后里面会写入爬虫代码
│ └── init.py
└── scrapy.cfg # scrapy项目配置信息

  1. 创建爬虫文件

cd firstBlood

  1. 创建主文件
scrapy genspider 爬虫文件的名称(自定义一个名字即可) 起始url (随便写一个网址即可)

比如:

scrapy genspider baidu www.baidu.com

1.2 修改配置文件

打开settings.py:

    • 不遵从robots协议:ROBOTSTXT_OBEY = False
    • 指定输出日志的类型:LOG_LEVEL = ‘ERROR’
    • 指定UA:USER_AGENT = ‘xxxxxx’

1.3 启动程序

scrapy crawl 文件名(我这里是baidu)

2. Scrapy + Selenium

我们现在来进行基础的数据采集,我这里准备采集有关“三只羊”的资讯信息和详情内容:
在这里插入图片描述

2.1 通过scrapy异步爬取url

主文件baidu.com:

import scrapy
from ..items import FirstItemclass BaiduSpider(scrapy.Spider):name = "baidu"allowed_domains = ["www.baidu.com"]start_urls = ['http://www.baidu.com/s?ie=utf-8&medium=0&rtt=1&bsst=1&rsv_dl=news_t_sk&cl=2&wd=%E4%B8%89%E5%8F%AA%E7%BE%8A&tn=news&rsv_bp=1&oq=&rsv_sug3=12&rsv_sug1=5&rsv_sug7=101&rsv_sug2=0&rsv_btype=t&f=8&inputT=1395&rsv_sug4=1395']def parse(self, response):text = response# 获取数据contents = text.xpath('//a[@class="news-title-font_1xS-F"]')for c in contents:url = c.xpath('@href').extract_first()title = c.xpath('@aria-label').extract_first()items = FirstItem()items['url'] = urlitems['title'] = titleyield scrapy.Request(url=url, callback=self.detail_parse, meta={'item': items})def detail_parse(self, response):print(response)

items:

import scrapyclass FirstItem(scrapy.Item):url = scrapy.Field()title = scrapy.Field()

2.2 中间件结合selenium

假设现在,详情页面是涉及到js加密的,这该如何解决呢?

聪明的小伙伴已经想到了:是selenium!

只要模拟的好,所见即所得

那么我们该如何做呢?

众所周知,在Scrapy框架中,有一种名叫中间件的东西,他有什么用呢:

此中间件可以在请求之前、响应之前截取请求/响应信息,并在此做一系列操作

也就是说,在返回给detail_parse之前,我们可以重新处理响应数据

来看代码:

baidu.py

class BaiduSpider(scrapy.Spider):name = "baidu"# allowed_domains = ["www.baidu.com"]start_urls = ['http://www.baidu.com/s?ie=utf-8&medium=0&rtt=1&bsst=1&rsv_dl=news_t_sk&cl=2&wd=%E4%B8%89%E5%8F%AA%E7%BE%8A&tn=news&rsv_bp=1&oq=&rsv_sug3=12&rsv_sug1=5&rsv_sug7=101&rsv_sug2=0&rsv_btype=t&f=8&inputT=1395&rsv_sug4=1395']# 实例化浏览器对象bro = webdriver.Chrome()def parse(self, response):text = response# 获取数据contents = text.xpath('//a[@class="news-title-font_1xS-F"]')items = FirstItem()for c in contents:url = c.xpath('@href').extract_first()title = c.xpath('@aria-label').extract_first()items['url'] = urlitems['title'] = titleyield scrapy.Request(url=url, callback=self.detail_parse, meta={'item': items} ,  dont_filter=True)def detail_parse(self, response):item = response.meta['item']content = response.xpath('//div[@class="EaCvy"]//text()').extract_first()item['content'] = contentyield item# 重写父类方法def closed(self, spider):print('整个操作结束!!!')self.bro.quit()

重点:

  1. bro = webdriver.Chrome()这里实例化了一个浏览器对象

  2. 这里是解析完url后,再一次手动发起请求

yield scrapy.Request(url=url, callback=self.detail_parse, meta={'item': items} ,  dont_filter=True)
  1. 这是重写的父类方法
    def closed(self, spider):print('整个操作结束!!!')self.bro.quit()  # 执行完就关闭浏览器

最重要的是中间件的写法:

pipelines.py

import time
from scrapy import signals
from itemadapter import is_item, ItemAdapter
from scrapy.http import HtmlResponse
class FirstDownloaderMiddleware:def process_request(self, request, spider):  # 这里的spider就是指的主对象程序,也就是前面发出请求的类对象return Nonedef process_response(self, request, response, spider):# 第一次请求不触发seleniumif request.url != spider.start_urls[0]:bro = spider.bro  # selenium浏览器对象bro.get(request.url)time.sleep(3)source = bro.page_source# 重新封装一个响应对象new_response = HtmlResponse(url=request.url, body=source, request=request, encoding='utf-8')return new_responsereturn response

items.py

import scrapy
class FirstItem(scrapy.Item):url = scrapy.Field()title = scrapy.Field()content = scrapy.Field()

3. 总结

其实想要实现scrapy和selenium共同完成爬虫任务还是比较简单的。

最重要的是理解中间件的性质,并且能够在合适的地方去修改请求/响应内容。

在遇到比较复杂的页面时,可以尝试使用scrapy + selenium的模式进行爬取。

将两者结合使用,能够弥补彼此的不足,发挥出更大的优势。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • stm32g431rbt6芯片中VREF+是什么?在电路中怎么设计?
  • SEGGERS实时系统embOS推出Linux端模拟器
  • redis学习(010 实战:黑马点评:缓存:封装redis工具类)
  • python学习笔记目录
  • 【ArcGISProSDK】初识
  • MATLAB系列08:输入/输入函数
  • 课题研判:多维度视角下的深度剖析
  • Linux_bash的一些特殊符号
  • 基于SpringBoot+Vue的篮球馆会员信息管理系统
  • Python编码系列—Python组合模式:构建灵活的对象组合
  • Java进阶之集合框架(Set)
  • LLM - 理解 多模态大语言模型(MLLM) 的 评估(Evaluation) 与相关技术 (六)
  • 关于Element-ui中el-table出现的表格错位问题解决
  • #nginx配置案例
  • 揭开 Vue 3 中大量使用 ref 的隐藏危机
  • Consul Config 使用Git做版本控制的实现
  • Hibernate【inverse和cascade属性】知识要点
  • in typeof instanceof ===这些运算符有什么作用
  • VuePress 静态网站生成
  • 分布式任务队列Celery
  • 聊一聊前端的监控
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 使用Gradle第一次构建Java程序
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 用element的upload组件实现多图片上传和压缩
  • 《码出高效》学习笔记与书中错误记录
  • puppet连载22:define用法
  • Semaphore
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​【已解决】npm install​卡主不动的情况
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • # 计算机视觉入门
  • #### golang中【堆】的使用及底层 ####
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • (2024,Vision-LSTM,ViL,xLSTM,ViT,ViM,双向扫描)xLSTM 作为通用视觉骨干
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (ZT)一个美国文科博士的YardLife
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (自用)仿写程序
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .apk文件,IIS不支持下载解决
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .net Signalr 使用笔记
  • .Net Web项目创建比较不错的参考文章
  • .Net 应用中使用dot trace进行性能诊断
  • .NET程序集编辑器/调试器 dnSpy 使用介绍
  • .net和jar包windows服务部署
  • .NET未来路在何方?
  • .so文件(linux系统)
  • @SentinelResource详解
  • [ 物联网 ]拟合模型解决传感器数据获取中数据与实际值的误差的补偿方法
  • []使用 Tortoise SVN 创建 Externals 外部引用目录
  • [2016.7 test.5] T1