selenium自动化测试+OCR-获取图片页面小说

news2024/11/25 23:29:02

随着爬虫技术的发展,反爬虫技术也越来越高。

目前有些网站通过自定义字体库的方式实现反爬,主要表现在页面数据显示正常,但是页面获取到的实际数据是别的字符或者是一个编码。
这种反爬需要解析网站自己的字体库,对加密字符使用字体库对应字符替换。需要制作字体和基本字体间映射关系。
还有些网站通过图片加载内容的方式实现反爬,想要获取网页内容,可以结合使用OCR技术获取图片文字内容。

第一步:先获取网页内容截图

结合之前《selenium自动化测试-获取动态页面小说》相关的文章代码,改造下,封装成一个新方法,只获取小说网页内容截图,按章节ID分目录保存每页截图文件。

依旧采用拆分步骤细化功能模块封装方法编写代码,便于后续扩展功能模块,代码中缺少的封装方法代码,详情参考之前的《selenium自动化测试》文章。

def spider_novel_content_save_image(req_dict):
    '''
    @方法名称: 爬取小说章节明细内容,保存内容截图文件
    @中文注释: 爬取小说章节明细内容,保存内容截图文件
    @入参:
        @param req_dict dict 请求容器
    @出参:
        @返回状态:
            @return 0 失败或异常
            @return 1 成功
        @返回错误码
        @返回错误信息
        @param rsp_dict dict 响应容器
    @作    者: PandaCode辉
    @weixin公众号: PandaCode辉
    @创建时间: 2023-09-26
    @使用范例: spider_novel_content_save_image(req_dict)
    '''

    try:
        if (not type(req_dict) is dict):
            return [0, "111111", "请求容器参数类型错误,不为字典", [None]]
        # 章节目录文件名
        json_name = req_dict['novel_name'] + '.json'
        # 检查文件是否存在
        if os.path.isfile(json_name):
            print('json文件存在,不用重新爬取小说目录.')
        else:
            print('json文件不存在')
            # 爬取小说目录
            spider_novel_mulu(req_dict)
        # 读取json文件
        with open(json_name, 'r') as f:
            data_str = f.read()
        # 转换为字典容器
        mulu_dict = json.loads(data_str)

        # 在列表中查找指定元素的下标,未完成标志下标
        flag_index = mulu_dict['flag'].index('0')
        print(flag_index)
        # 章节总数
        chap_len = len(mulu_dict['chap_url'])
        # 在列表中查找指定元素的下标
        print('章节总数:', chap_len)

        # 截图目录
        screenshot_dir = os.path.join(os.path.dirname(__file__), 'screenshot')
        if not os.path.exists(screenshot_dir):
            os.makedirs(screenshot_dir)

        print('打开浏览器驱动')
        open_driver()
        # 循环读取章节
        for chap_id in range(flag_index, chap_len):
            print('chap_id : ', chap_id)
            # 章节url
            chap_url = mulu_dict['chap_url'][chap_id]
            # 截图目录,根据章节ID分类保存
            chap_id_dir = os.path.join(screenshot_dir, str(chap_id))
            if not os.path.exists(chap_id_dir):
                os.makedirs(chap_id_dir)
            # 打开网址网页
            print('打开网址网页')
            driver.get(chap_url)
            # 等待6秒启动完成
            driver.implicitly_wait(6)
            print('随机休眠')
            # 随机休眠 暂停0-2秒的整数秒
            time.sleep(random.randint(0, 2))

            # 章节分页url列表初始化
            page_href_list = []
            # 根据url地址获取网页信息
            chap_rst = get_html_by_webdriver(chap_url)
            time.sleep(3)
            if chap_rst[0] != 1:
                # 跳出循环爬取
                break
            chap_html_str = chap_rst[3][0]
            # 使用BeautifulSoup解析网页数据
            chap_soup = BeautifulSoup(chap_html_str, "html.parser")
            # 章节内容分页数和分页url
            # 获取分页页码标签下的href元素取出
            page_href_list_tmp = chap_soup.select("div#PageSet > a")
            all_page_cnt = len(page_href_list_tmp)
            print("分页页码链接数量:" + str(all_page_cnt))
            # 去除最后/后面数字+.html
            tmp_chap_url = re.sub(r'(\d+\.html)', '', chap_url)
            for each in page_href_list_tmp:
                if len(each) > 0:
                    chap_url = tmp_chap_url + str(each.get('href'))
                    print("拼接小说章节分页url链接:" + chap_url)
                    # 判断是否已经存在列表中
                    if not chap_url in page_href_list:
                        page_href_list.append(chap_url)
            print("分页url链接列表:" + str(page_href_list))

            # 网页长宽最大化,保证截图是完整的,不会出现滚动条
            S = lambda X: driver.execute_script('return document.body.parentNode.scroll' + X)
            driver.set_window_size(S('Width'), S('Height'))

            # 章节页码,首页
            page_num = 1
            # 章节内容截图
            image_file = os.path.join(chap_id_dir, str(page_num) + '.png')
            # 元素定位
            chap_content_element = driver.find_element(By.ID, 'content')
            print(chap_content_element)
            # 元素截图
            chap_content_element.screenshot(image_file)

            # 分页列表大于0
            if len(page_href_list) > 0:
                for chap_url_page in page_href_list:
                    print("chap_url_page:" + chap_url_page)
                    time.sleep(3)

                    # 打开网址网页
                    print('打开网址网页')
                    driver.get(chap_url_page)
                    # 等待6秒启动完成
                    driver.implicitly_wait(6)
                    print('随机休眠')
                    # 随机休眠 暂停0-2秒的整数秒
                    time.sleep(random.randint(0, 2))

                    # 章节页码
                    page_num += 1
                    # 章节内容截图
                    image_file = os.path.join(chap_id_dir, str(page_num) + '.png')
                    # 元素定位
                    chap_content_element = driver.find_element(By.ID, 'content')
                    print(chap_content_element)
                    # 元素截图
                    chap_content_element.screenshot(image_file)

            # 爬取明细章节内容截图成功后,更新对应标志为-2-截图已完成
            mulu_dict['flag'][chap_id] = '2'
        print('关闭浏览器驱动')
        close_driver()

        # 转换为json字符串
        json_str = json.dumps(mulu_dict)
        # 再次写入json文件,保存更新处理完标志
        with open(json_name, 'w', encoding="utf-8") as json_file:
            json_file.write(json_str)
        print("再次写入json文件,保存更新处理完标志")
        # 返回容器
        return [1, '000000', '爬取小说内容截图成功', [None]]

    except Exception as e:
        print('关闭浏览器驱动')
        close_driver()
        # 转换为json字符串
        json_str = json.dumps(mulu_dict)
        # 再次写入json文件,保存更新处理完标志
        with open(json_name, 'w', encoding="utf-8") as json_file:
            json_file.write(json_str)
        print("再次写入json文件,保存更新处理完标志")
        print("爬取小说内容异常," + str(e))
        return [0, '999999', "爬取小说内容截图异常," + str(e), [None]]

第二步:通过OCR接口识别截图

结合之前《PaddleOCR学习笔记3-通用识别服务》和《selenium自动化测试-获取动态页面小说》相关的文章代码,改造下,封装成一个新方法,通过OCR接口识别小说网页内容截图,然后写入文件保存。

依旧采用拆分步骤细化功能模块封装方法编写代码,便于后续扩展功能模块,代码中缺少的封装方法代码,详情参考之前的《selenium自动化测试》文章。

# 模拟http请求
def requests_http(file_path, file_name, url):
    full_file_path = os.path.join(file_path, file_name)
    # 请求参数,文件名
    req_data = {'upload_file': open(full_file_path, 'rb')}

    # 模拟http请求
    rsp_data = requests.post(url, files=req_data)
    # print(rsp_data.text)
    result_dict = json.loads(rsp_data.text)
    # print(result_dict)
    return result_dict


def spider_novel_content_by_ocr(req_dict):
    '''
    @方法名称: 通过OCR接口获取小说章节明细内容文字
    @中文注释: 读取章节列表json文件,通过OCR接口获取小说章节明细内容文字,保存到文本文件
    @入参:
        @param req_dict dict 请求容器
    @出参:
        @返回状态:
            @return 0 失败或异常
            @return 1 成功
        @返回错误码
        @返回错误信息
        @param rsp_dict dict 响应容器
    @作    者: PandaCode辉
    @weixin公众号: PandaCode辉
    @创建时间: 2023-09-26
    @使用范例: spider_novel_content_by_ocr(req_dict)
    '''

    try:
        if (not type(req_dict) is dict):
            return [0, "111111", "请求容器参数类型错误,不为字典", [None]]
        # 章节目录文件名
        json_name = req_dict['novel_name'] + '.json'
        # 检查文件是否存在
        if os.path.isfile(json_name):
            print('json文件存在,不用重新爬取小说目录.')
        else:
            print('json文件不存在')
            # 爬取小说目录
            spider_novel_mulu(req_dict)
        # 读取json文件
        with open(json_name, 'r') as f:
            data_str = f.read()
        # 转换为字典容器
        mulu_dict = json.loads(data_str)
        """
            关于open()的mode参数:
            'r':读
            'w':写
            'a':追加
            'r+' == r+w(可读可写,文件若不存在就报错(IOError))
            'w+' == w+r(可读可写,文件若不存在就创建)
            'a+' ==a+r(可追加可写,文件若不存在就创建)
            对应的,如果是二进制文件,就都加一个b就好啦:
            'rb'  'wb'  'ab'  'rb+'  'wb+'  'ab+'
        """
        file_name = req_dict['novel_name'] + '.txt'
        # 在列表中查找指定元素的下标,2-截图完成,标志下标
        flag_index = mulu_dict['flag'].index('2')
        print(flag_index)
        # 2-截图完成,标志下标为0,则为第一次爬取章节内容,否则已经写入部分,只能追加内容写入文件
        # 因为章节明细内容很多,防止爬取过程中间中断,重新爬取,不用重复再爬取之前成功写入的数据
        if flag_index == 0:
            # 打开文件,首次创建写入
            fo = open(file_name, "w+", encoding="utf-8")
        else:
            # 打开文件,再次追加写入
            fo = open(file_name, "a+", encoding="utf-8")
        # 章节总数
        chap_len = len(mulu_dict['chap_url'])
        # 在列表中查找指定元素的下标
        print('章节总数:', chap_len)

        # 截图目录
        screenshot_dir = os.path.join(os.path.dirname(__file__), 'screenshot')
        # 循环读取章节
        for chap_id in range(flag_index, chap_len):
            # 识别成功标志
            succ_flag = False
            # 章节标题
            chap_title = mulu_dict['chap_title'][chap_id]
            print('chap_id : ', chap_id)
            # # 写入文件,章节标题
            fo.write("\n" + chap_title + "\r\n")
            # 截图目录,根据章节ID分类保存
            chap_id_dir = os.path.join(screenshot_dir, str(chap_id))
            # 列出目录下的所有文件和文件夹
            file_list = os.listdir(chap_id_dir)
            # 章节目录下文件列表大于0
            if len(file_list) > 0:
                for file_name in file_list:
                    print("file_name:" + file_name)
                    time.sleep(3)

                    url = "http://127.0.0.1:5000/upload/"
                    # 模拟http请求
                    result_dict = requests_http(chap_id_dir, file_name, url)
                    print(result_dict)
                    # 识别成功
                    if result_dict['error_code'] == '000000':
                        succ_flag = True
                        result_list = result_dict['result']
                        for data in result_list:
                            print(data['text'])
                            # 将识别结果,逐行写入文件,章节内容
                            fo.write(data['text'] + "\n")
                    else:
                        succ_flag = False
                        print('识别失败异常.')
            # 识别成功则更新
            if succ_flag:
                # 爬取明细章节内容成功后,更新对应标志为-1-已完成
                mulu_dict['flag'][chap_id] = '1'
        print('关闭浏览器驱动')
        close_driver()
        # 关闭文件
        fo.close()
        print("循环爬取明细章节内容,写入文件完成")
        # 转换为json字符串
        json_str = json.dumps(mulu_dict)
        # 再次写入json文件,保存更新处理完标志
        with open(json_name, 'w', encoding="utf-8") as json_file:
            json_file.write(json_str)
        print("再次写入json文件,保存更新处理完标志")
        # 返回容器
        return [1, '000000', '爬取小说内容成功', [None]]

    except Exception as e:
        print('关闭浏览器驱动')
        close_driver()
        # 关闭文件
        fo.close()
        # 转换为json字符串
        json_str = json.dumps(mulu_dict)
        # 再次写入json文件,保存更新处理完标志
        with open(json_name, 'w', encoding="utf-8") as json_file:
            json_file.write(json_str)
        print("再次写入json文件,保存更新处理完标志")
        print("爬取小说内容异常," + str(e))
        return [0, '999999', "爬取小说内容异常," + str(e), [None]]

第三步:运行效果

第四步:总结

目前很多网站都有基本的反爬策略,常见就是验证码、JS参数加密这两种。
爬虫本身会对网站增加一定的压力,所以也应该合理设定爬取速率,尽量避免对目标网站造成麻烦,影响网站正常使用,一定注意自己爬虫的姿势。

敬畏法律,遵纪守法,从我做起。

 最后说明:上述文章仅供学习参考,请勿用于商业用途,感谢阅读。

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

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

相关文章

图片编辑小程序源码/拼图小程序源码

图片编辑小程序源码,拼图小程序源码。全能、便捷的图片编辑工具。实现了图片裁剪、添加文字、涂鸦、拼长图、拼相框等图片编辑功能,另外还有一个简易的表情包制作功能。 主要有以下几个功能:图片裁剪、添加文字、涂鸦功能、拼长图、拼相框、表…

TCPIP状态转换

一个TCP连接在其生命周期中经过了一系列的状态跃迁。一个TCP连接的状态包括: LISTEN :表示正在等待来自任何远程TCP和端口的连接请求,调用listen后套接字出于监听状态SYN_SENT : 表示在发送了连接请求后,正在等待匹配的连接请求…

代码随想录Day03 | 链表基础1 LeetCode T203 移除链表元素 T707设计链表 T206 反转链表

本题思路和解答主要来源于: 代码随想录 (programmercarl.com) LeetCode T203 移除链表元素 题目链接:203. 移除链表元素 - 力扣(LeetCode) 首先我们回顾一下单向链表,每个链表有一个指针域和一个数据域,在内存中是呈现不连续排列的,对比之前的数组,链…

一百八十八、Hive——HiveSQL查询表中的日期是星期几(亲测,附截图)

一、目的 指标需要查询以工作日和周末维度的数据统计,因此需要根据数据的日期判断这一天属于星期几,周一到周五为工作日,周六到周日为周末 二、SQL查询 (一)SQL语句 selectday,case when pmod(datediff(create_tim…

【CentOS7】基于python2,3安装docker-compose

【CentOS7】基于python2,3安装docker-compose 前言【基于python2.7】1.安装pip服务2.安装docker-compose服务 【基于python3】1.安排python32.检查是否安装成功3.安排python-pip3并升级4.执行如下命令安装 docker-compose:5.查看docker-compose 版本 前言…

【IDEA】IDEA 单行注释开头添加空格

操作 打开 IDEA 的 Settings 对话框(快捷键为CtrlAltS);在左侧面板中选择Editor -> Code Style -> Java;在右侧面板中选择Code Generation选项卡;将Line comment at first column选项设置为false使注释加在行开…

Hazelcast系列(三):hazelcast管理中心

系列文章 Hazelcast系列(一):初识hazelcast Hazelcast系列(二):hazelcast集成 Hazelcast系列(三):hazelcast管理中心 目录 前言 平台搭建 测试 其他 参考 总结 前言 前面,我们通过几种配置方式(Hazelcast系…

解决jetbrains-toolbox缺失修改安装路径默认安装C盘问题

前一阵子使用 ToolBox 的时候还可以修改 IDEA 的安装路径,但是过了一段时间在家里电脑发现无法没有了修改安装路径这一选项,庞大的 IDEA 软件累积起来C盘的空间也日趋臃肿,有强迫症的程序员怎么会让它安装在C盘呢? 如图所示&…

1024程序员节之天马低代码开发者大赛篇

卡奥斯第二届1024程序员节正在火热进行中!本次活动由四个线上活动分会场线下会场组成,今天向大家详细介绍一下四大线上分会场中的“低代码分会场”~ 天马低代码开发者大赛于2023年9月22日至10月20日12: 00进行,活动设立能源和组态两个赛道&a…

《安富莱嵌入式周报》第323期:NASA开源二代星球探索小车, Matlab2023b,蓝牙照明标准NLC, Xilinx发布电机套件,Clang V17发布

周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版: https://www.bilibili.com/video/BV1vp4y1F7qD 《安富莱嵌入式周报》第323期:NASA开源…

Docker-基本了解

Docker-基本了解 一、基本概念1、镜像2、容器 二、执行流程三、体系结构 一、基本概念 Docker是容器化平台,提供应用打包,部署与运行应用的容器化平台,应用程序通过docker engine(Docker 引擎获取可用资源)&#xff0…

磁铁产品上架亚马逊做什么认证?磁铁产品16CFR1262认证标准

玩具产品就需要做CPC认证:CPSIAASTMF9634.38磁铁标准(玩具安全标准消费者安全规范。) 法规要求 必须根据ASTM F963-17第8.25.1节至第8.25.3节中概述的程序对所有磁体产品进行测试。 《消费品安全法》(CPSA)第14&…

【安卓】开发跳过广告app,具备“李跳跳”app的部分功能

前言 现在手机的开屏广告还是挺多的,还有应用内弹出广告,青少年模式等,市面上很多跳过广告app下架了,我利用工作闲暇时间开发了自己用的app,不传播,分享知识! 实现思路 利用手机的无障碍服务…

ARM day1

1.复习今日内容 2.搭建汇编环境 下发资料-》工具软件 -》汇编环境搭建 3.安装Ubuntu下的交叉编译工具链 思维导图:

MQ - 31 基础功能: 优先级队列的设计

文章目录 导图概述什么是优先级队列如何设计实现优先级队列业务实现优先级队列的效果内核支持优先级队列RabbitMQ 中优先级队列的实现总结导图 概述 当我们需要在业务中对消息设置优先级,让优先级高的消息能被优先消费,此时就需要用到消息队列中优先级队列的特性。 为了了解…

玩转Mysql系列 - 第23篇:mysql索引管理详解

这是Mysql系列第23篇。 环境:mysql5.7.25,cmd命令中进行演示。 代码中被[]包含的表示可选,|符号分开的表示可选其一。 关于索引的,可以先看一下前2篇文章: 什么是索引? mysql索引原理详解 本文主要介…

Sui资助申请指南,310万美元资助金已成功申领

Sui基金会致力于资助开发者、构建者、教育工作者、研究人员以及其他推动和推广Sui生态发展的社区成员。立即申请:https://airtable.com/shrkLWBRNPL89f0SX 资助计划类型 构建者资助计划 通过推动Sui的全球采用,帮助引导下一个十亿用户进入Web3的项目。…

外包干了3个月,技术退步明显。。。。。

先说一下自己的情况,大专生,17年通过校招进入广州某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

使用 Microsoft 365 进行移动设备管理

什么是 Microsoft 365 的移动设备管理 移动设备通过允许员工访问文件、电子邮件、联系人等,在帮助员工随时随地工作方面发挥了巨大作用,允许员工将公司拥有的移动设备用于工作目的可能意味着允许员工在不在办公场所时从外部网络访问资源,这使…

人工智能在医疗中的应用:医院陪诊系统的前沿技术

人工智能在医疗领域的应用已经带来了巨大的变革,其中之一是医院陪诊系统。这些系统利用机器学习和自然语言处理等人工智能技术,改善了患者体验,提高了医疗机构的效率。本文将讨论医院陪诊系统的前沿技术,并提供一个简单的示例代码…