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

不会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 FirstItem


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']

    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'] = url
            items['title'] = title
            yield scrapy.Request(url=url, callback=self.detail_parse, meta={'item': items})

    def detail_parse(self, response):
        print(response)

items:

import scrapy


class 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'] = url
            items['title'] = title

            yield 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'] = content
        yield 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 None

    def process_response(self, request, response, spider):
        # 第一次请求不触发selenium
        if 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_response
        return response

items.py

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

3. 总结

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

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

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

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


http://www.kler.cn/a/311767.html

相关文章:

  • 【电力系统】永磁同步电机调速系统带有扰动观测器
  • MySQL 中的索引下推功能
  • 【大数据学习 | HBASE高级】region split机制和策略
  • 多线程和线程同步复习
  • BFD8122防爆轻便移动工作灯
  • SQLI LABS | Less-40 GET-BLIND Based-String-Stacked
  • 前端框架对比和选择?
  • [学习笔记]树链剖分(简易版) 及其LCA
  • Redis实践之缓存:设置缓存过期策略
  • 计算机网络33——文件系统
  • sqli-labs靶场自动化利用工具——第13关
  • RabbitMQ 和 Kafka 的详细对比表格
  • 消息队列:如何确保消息不会丢失?
  • 自然语言处理实战项目全解析
  • 阻止冒泡事件
  • Python中的异步编程:从基础知识到高级应用
  • vi | vim基本使用
  • 视频相关处理
  • 基于Delphi的题库生成系统
  • spark读mongodb
  • HTB-Jerry(tomcat war文件、msfvenom)
  • Unity制作角色溶解变成光点消失
  • GPT提示词分享 —— 深度思考助手
  • 【Vue】VueRouter路由
  • Spring系统学习(一)——初识Spring框架
  • 第五届“马栏山杯”国际音视频算法大赛创新应用赛投票环节正式启动啦!