0

    使用 Scrapy + Selenium 爬取动态渲染的页面

    2023.07.08 | admin | 120次围观

    更多技术文章:Redirecting...

    背景

    在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生js实现鼠标移上去显示详细信息,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值。但是通过观察我们会发现,通过浏览器进行url请求发送则会加载出对应的动态加载出的数据。那么如果我们想要在scrapy也获取动态加载出的数据,则必须使用selenium创建浏览器对象,然后通过该浏览器对象进行请求发送,获取动态加载的数据值. 本文分享scrapy的介绍和如何配合selenium实现动态网页的爬取。

    Scrapy

    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。其最初是为了 页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。

    Scrapy 安装并运行

    安装 通过pip install Scrapy 安装即可, Ubuntu安装需要安装依赖sudo apt-get install python-dev python-pip libxml2-dev libxslt1-dev zliblg-dev libffi-dev libssl-dev;

    创建项目: scrapy startproject project_name;

    创建爬虫: 进入项目根目录 scrapy genspider spider_name sprder_domian;

    目录介绍;

    project_folder -- 项目文件夹名称
    |
    |──project_name -- 该项目的python模块,一般和项目文件夹名称相同
    |  |
    |  |──spider -- 放置spider代码的包,以后所有的爬虫,都存放在这个里面
    |  |
    |  |──items.py -- 用来存放爬虫怕写来的数据的模型
    |  |
    |  |──middlewares.py -- 用来存放各种中间件的文件
    |  |
    |  |──pipelines.py -- 用来对items里面提取的数据做进一步处理,如保存到本地磁盘等
    |  |
    |  |──settings.py -- 本爬虫的一些配置信息(如请求头、多久发送一次请求、ip代理池等)
    |
    |──scrapy.cfg -- 项目的配置文件
    

    01

    Scrapy执行流程

    Scrapy中的数据流由执行引擎控制,其过程如下:

    (从第二步)重复直到调度器中没有更多的请求(Requests)。

    02

    Scrapy架构图

    03

    中间件架构

    Selenium

    Selenium有很多东西,但从本质上讲,它是一个 Web 浏览器自动化工具集,它使用可用的最佳技术远程控制浏览器实例并模拟用户与浏览器的交互。它允许用户模拟最终用户执行的常见活动;在字段中输入文本,选择下拉值和复选框,并单击文档中的链接。它还提供了许多其他控件,例如鼠标移动、任意 JavaScript 执行等等。

    01

    selenium 安装

    安装 pip install selenium

    02

    驱动安装

    使用selenium驱动chrome浏览器需要下载chromedriver,而且chromedriver版本需要与chrome的版本对应,版本错误的话则会运行报错。

    03

    chrome

    下载chromedriver可以通过淘宝镜像地址:

    最新的镜像与Chrome同名,尽量选择版本相近的避免兼容问题,镜像下notes.txt可查看当前驱动支持的版本。

    04

    其他浏览器驱动

    Opera:http://npm.taobao.org/mirrors/operadriver/
    IE:   http://selenium-release.storage.googleapis.com/index.html
    

    使用requests爬取动态渲染的页面

    import requests
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
        'Accept-Encoding': 'gzip',
        'Connection': 'keep-alive',
        'Host': 'www.aqistudy.cn',
    }
    url = "https://192.168.1.1/aqistudy/monthdata.php?city=北京"
    res = requests.get(url, headers=header)
    if res.status_code == 200:
        print("请求成功")
        with open("aqistudy.txt", encoding="utf8", mode='w+') as f:
            f.write(res.text)
    else:
        print("请求失败")
    

      
    月份 AQI 质量等级 PM2.5 PM10

    var muwSVVIti = 'GETMONTHDATA';
      endebug(false, function () {
        document.write('检测到非法调试, 请关闭调试终端后刷新本页面重试!');
        document.write("
    "); document.write("Welcome for People, Not Welcome for Machine!"); diwAafiP = true; }); txsdefwsw(); document.onkeydown = function() { if ((e.ctrlKey) && (e.keyCode == 83)) { alert("检测到非法调试,CTRL + S被管理员禁用"); return false; } } document.onkeydown = function() { var e = window.event || arguments[0]; if (e.keyCode == 123) { alert("检测到非法调试,F12被管理员禁用"); return false; } } document.oncontextmenu = function() { alert('检测到非法调试,右键被管理员禁用'); return false; } }

    可以看到 返回的页面源码中 只有一个天气表格的框架, 没有我们需要的天气信息. 而且出现了被检测的信息. 出现这种情况 是因为:

    ● 目标网页是动态渲染的页面, 所以我们只能看到天气表格的框架js实现鼠标移上去显示详细信息,看不到具体的信息

    ● 目标网页检测到selenium 禁止调试

    Scrapy + Selenium

    运行一个Scrapy的项目

    import scrapy
    class ApistudyMainSpider(scrapy.Spider):
        name = 'apistudy_main'
        allowed_domains = ['192.168.1.1']
        def start_requests(self):
            start_url = r'https://192.168.1.1/aqistudy/monthdata.php?city=北京'
            yield scrapy.Request(url=start_url, callback=self.parse, dont_filter=True)
        def parse(self, response):
            yield {'text': response.text}
    

    class AqistudyPipeline(object):
        # def process_item(self, item, spider):
        #     return item
        def open_spider(self, spider):
            self.file = open('my.html', 'w', encoding='utf-8')
        def close_spider(self, spider):
            self.file.close()
        def process_item(self, item, spider):
            self.file.write(str(item['text']))
    

    class RandomHeaderMiddleWare:
        def __init__(self):
            self.user_agents = USER_AGENTS
        def process_request(self, request, spider):
            request.headers['User-Agent'] = random.choice(self.user_agents)
            # 如果IP被限制, 可以在此下载中间件添加代理
            option = webdriver.ChromeOptions()
            option.add_argument('--headless')       # 无界面运行
            option.add_argument('--disable-gpu')    # 禁止gpu加速
            option.add_argument("no-sandbox")       # 取消沙盒模式
            option.add_argument("disable-blink-features=AutomationControlled")  # 禁用启用Blink运行时的功能
            option.add_experimental_option('excludeSwitches', ['enable-automation'])    # 开发者模式
            driver = webdriver.Chrome(options=option)
            # 移除 `window.navigator.webdriver`. scrapy 默认为True
            driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
                "source": """
                    Object.defineProperty(navigator, 'webdriver', {
                      get: () => undefined
                    })
                  """
            })
            driver.get(request.url)
            driver.implicitly_wait(5)
            content = driver.page_source
            driver.quit()
            return HtmlResponse(request.url, encoding="utf-8", body=content, request=request)
        def process_response(self, request, response, spider):
            return response
        def process_exception(self, request, exception, spider):
            return None
    

    SPIDER_MIDDLEWARES = {
        'aqistudy.middlewares.AqistudySpiderMiddleware': 543,
    }
    DOWNLOADER_MIDDLEWARES = {
        'aqistudy.middlewares.AqistudyDownloaderMiddleware': 543,
        'aqistudy.middlewares.RandomHeaderMiddleWare': 545,     # 添加下载中间件
    }
    ROBOTSTXT_OBEY = False
    

     ...>
                    
    月份 AQI 质量等级 PM2.5 PM10
    2013-12 100 轻度污染 73 97

    总结

    在撰写爬虫程序时, 遇到动态渲染的页面我们可以使用Scrapy+Selenium对页面规避反爬策略和爬取页面信息. 虽然webdriver影响到了Scrapy 的运行速度, 我们还可以使用scrapy-redis让我们的爬虫变成分布式以提高效率。

    文件传输助手:Redirecting...

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    标签: seleniumscrapy
    发表评论