• Selenium爬虫实践(踩坑记录)之ajax请求抓包、浏览器退出


    上一篇: 使用Selenium截取网页上的图片

    前言

    最近在搞公司内部系统,累的一批,需要从另一个内部系统导出数据存到数据库做分析,有大量的数据采集工作,又没办法去直接拿到那个系统的接口,太难了,只能爬虫,但是cookie还经常失效,为了不每次登录失效就来找我重新注入Cookie,我写了一个手机版的网页,用来控制后台的selenium自动登录,截取token和cookie。

    ajax请求抓包方案

    搜索资料的过程真的痛苦,不过还好这时间没有白花,最终还是解决了问题……

    根据找到的资料,有以下几种方法可以在Selenium中抓取ajax请求中的数据

    • 使用本地代理:browsermob-proxy (本文采用的方法)
    • 使用selenium的执行js功能注入 ajax hook 并执行,然后本地开一个服务器接收拦截到的ajax数据(见第三个参考资料)
    • 用第三方库selenium-wire,这个是一个GitHub上的开源项目,可以直接截取response_code和body,原理应该走的也是代理
    • 开启selenium的性能抓取,在性能日志里面可以做改动,以拦截response_body(详见第一个参考资料)

    使用本地代理

    本文使用Browsermob-Proxy这个代理服务器,这个是用Java写的,有一个python封装的接口包可以方便交互……

    先去下载:https://github.com/lightbody/browsermob-proxy/releases

    安装python包:

    pip install browsermob-proxy
    

    在代码中使用,这里我截取了项目的部分代码,随便看看就好了,完整代码可以看官网文档或者参考资料~

    有几个需要注意的坑的地方,我在代码中标出了

    # 创建代理服务器
    self.server = Server(
        # Windows就是bat,如果Linux就是另一个不带后缀名的
        r'pathinrowsermob-proxy.bat',
        # 这里可以自定义端口
        options={'port': 9090}
    )
    # 这里启动服务器,等会机会要关掉,不然下次用就端口占用冲突了
    self.server.start()
    # 注意这里一定要 trustAllServers 不然等会selenium会报 error_tunnel 错误
    self.proxy = self.server.create_proxy(params={'trustAllServers': 'true'})
    
    # 设置selenium的代理
    options = ChromeOptions()
    options.add_argument('--ignore-certificate-errors')
    options.add_argument(f'--proxy-server={self.proxy.proxy}')
    self.driver = webdriver.Chrome(options=options)
    

    使用代理来进行抓包,我这个项目需要在ajax请求的header里面提取出token和cookie,截取了关键部分的代码如下:

    self.proxy.new_har('抓包名称 自己起一个', options={'captureHeaders': True, 'captureContent': True})
    
    # 找到需要点击的元素
    elem_query = self.driver.find_element_by_css_selector(elem_css_selector)
    elem_query.click()
    
    # 点击按钮后等待 并把数据取出来
    time.sleep(5)
    result = self.proxy.har
    
    data = {}
    
    for entry in result['log']['entries']:
        url = entry['request']['url']
        # 根据URL找到数据接口
        if 'xxx/query' in url:
            _response = entry['response']
            _content = _response['content']['text']
    
            for item in entry['request']['headers']:
                # 提取出header里面的 token
                if item['name'] == 'Authorization':
                    data['authorization'] = item['value']
                # 提取出header里面的 cookie
                if item['name'] == 'Cookie':
                    data['cookie'] = item['value']
            break
    
    print(data)
    

    以上代码同样不是完整代码,不过已经将具体抓包的过程完整表达出来,需要的同学可以根据自己的实际需求进行编码,只要能抓到数据,一切都好说~

    浏览器和代理服务器退出

    这个没啥好写的,但是也有一个小坑,水一下吧~

    从上面的代码里也可以看出来,我写了一个类来操作Selenium,程序执行完了肯定要把代理和服务器关了,不然selenium会留着一个 chromedriver.exe 的进程在后台占用资源,时间一长,系统内存都满了。

    我在类的__del__方法中加入了关闭代理服务器和浏览器的代码,如下:

    def __del__(self):
        print('SeleniumFxxkUnicom has been deleted.')
        self.proxy.close()
        self.server.stop()
        for win in self.driver.window_handles:
            self.driver.switch_to.window(win)
            self.driver.close()
        os.system('taskkill /im chromedriver.exe /F')
    

    注意这个循环的driver.close(),在__del__里是没办法正常执行driver.quit()的,按理说quit才是最好的退出方法,但是他还要导入什么鬼乱七八糟的模块,导致我在这个__del__里执行失败,于是只好曲线救国,先把全部标签页关闭,然后用系统命令结束掉进程…… 有点硬编码了,就这样吧,累了

    参考资料

    欢迎交流

    程序设计实验室专注于互联网热门新技术探索与团队敏捷开发实践,在公众号「程序设计实验室」后台回复 linux、flutter、c#、netcore、android、kotlin、java、python 等可获取相关技术文章和资料,同时有任何问题都可以在公众号后台留言~

    It never rains but it pours. 欢迎关注我的公众号:DealiAxy 提供更多技术文章
  • 相关阅读:
    为什么 Redis 重启后没有正确恢复之前的内存数据
    Redis的启动过程
    Redis 如何保持和MySQL数据一致
    redis集群节点宕机
    mysql 数据库管理
    mysqladmin 命令详解
    MySQL 编译安装
    mysql 数据库简介
    xtrabackup安装部署(二)
    Non-negative Partial Sums(单调队列)
  • 原文地址:https://www.cnblogs.com/deali/p/14367106.html
Copyright © 2020-2023  润新知