selenium自动化测试-获取动态页面小说
有的网站页面是动态加载的资源,使用bs4库只能获取静态页面内容,无法获取动态页面内容,通过selenium自动化测试工具可以获取动态页面内容。
参考之前的"bs4库爬取小说工具"文章代码,稍微修改下,就可以转成获取动态页面小说工具。
第一步:先确定目标网址
先找到小说目录页面。
网址首页:'https://www.bq0.net/'
目标小说目录页:'https://www.bq0.net/1bqg/898531870/'
第二步:确定章节目录和内容元素坐标
通过谷歌浏览器F12调试功能可以很快的定位页面元素位置.
第三步:编写代码
采用拆分步骤细化功能模块封装方法编写代码,便于后续扩展功能模块。
requests_webdriver.py:
# -*- coding: UTF-8 -*-
# selenium 自动化测试工具,爬取动态网页工具
import requests
import time
import re
from bs4 import BeautifulSoup
import random
import json
import os
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By # 打开驱动
def open_driver():
try:
# 连接浏览器web驱动全局变量
global driver
# Linux系统下浏览器驱动无界面显示,需要设置参数
# “–no-sandbox”参数是让Chrome在root权限下跑
# “–headless”参数是不用打开图形界面
'''
chrome_options = Options()
# 设为无头模式
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--disable-dev-shm-usage')
# 连接Chrome浏览器驱动,获取驱动
driver = webdriver.Chrome(chrome_options=chrome_options)
''' # 此步骤很重要,设置chrome为开发者模式,防止被各大网站识别出来使用了Selenium
options = Options()
# 去掉提示:Chrome正收到自动测试软件的控制
options.add_argument('disable-infobars')
# 以键值对的形式加入参数,打开浏览器开发者模式
options.add_experimental_option('excludeSwitches', ['enable-automation'])
# 打开浏览器开发者模式
# options.add_argument("--auto-open-devtools-for-tabs")
driver = webdriver.Chrome(chrome_options=options) # driver = webdriver.Chrome()
print('连接Chrome浏览器驱动')
# 浏览器窗口最大化
driver.maximize_window()
'''
1, 隐式等待方法
driver.implicitly_wait(最大等待时间, 单位: 秒)
2, 隐式等待作用
在规定的时间内等待页面所有元素加载;
3,使用场景:
在有页面跳转的时候, 可以使用隐式等待。
'''
driver.implicitly_wait(3)
# 强制等待,随机休眠 暂停0-3秒的整数秒,时间区间:[0,3]
time.sleep(random.randint(0, 3)) except Exception as e:
driver = None
print(str(e)) # 关闭驱动
def close_driver():
driver.quit()
print('关闭Chrome浏览器驱动') def get_html_by_webdriver(url_str):
'''
@方法名称: 根据浏览器驱动获取动态网页内容
@中文注释: 根据浏览器驱动获取动态网页内容
@入参:
@param url_str str url地址
@出参:
@返回状态:
@return 0 失败或异常
@return 1 成功
@返回错误码
@返回错误信息
@作 者: PandaCode辉
@创建时间: 2023-09-21
@使用范例: get_html_by_webdriver('www.baidu.com')
'''
try: if (not type(url_str) is str):
return [0, "111111", "url地址参数类型错误,不为字符串", [None]]
print('浏览器驱动不存在,重新打开浏览器驱动.')
# open_driver() # 打开网址网页
driver.get(url_str)
# 等待6秒启动完成
driver.implicitly_wait(6)
# 获取动态网页的html字符串信息
html_str = driver.page_source
print('开始关闭Chrome浏览器驱动')
# close_driver()
# print(html_str)
return [1, '000000', "获取动态网页内容成功", [html_str]]
except Exception as e:
print("获取动态网页内容异常超时," + str(e))
print('开始关闭Chrome浏览器驱动')
close_driver()
return [0, '999999', "获取动态网页内容异常超时," + str(e), [None]] def spider_novel_mulu(req_dict):
'''
@方法名称: 爬取小说章节目录
@中文注释: 根据参数爬取小说目录,保存到json文件
@入参:
@param req_dict dict 请求容器
@出参:
@返回状态:
@return 0 失败或异常
@return 1 成功
@返回错误码
@返回错误信息
@param rsp_dict dict 响应容器
@作 者: PandaCode辉
@创建时间: 2023-09-21
@使用范例: spider_novel_mulu(req_dict)
''' try:
if (not type(req_dict) is dict):
return [0, "111111", "请求容器参数类型错误,不为字典", [None]] open_driver()
# 根据url地址获取动态网页信息
rst = get_html_by_webdriver(req_dict['mulu_url'])
print('随机休眠')
# 随机休眠 暂停0-2秒的整数秒
time.sleep(random.randint(0, 2))
close_driver()
if rst[0] != 1:
return rst
html_str = rst[3][0]
# 使用BeautifulSoup解析网页数据
soup = BeautifulSoup(html_str, "html.parser") # 目录列表地址
tar_dir_href = soup.select(req_dict['tar_dir_href'])
# print(tar_dir_href)
tar_len = len(tar_dir_href)
print('初始爬取章节总数量:', tar_len) # 过滤章节下标初始化
del_index = 0
for dir_href in tar_dir_href:
chap_title = dir_href.text
# print(chap_title)
if '第1章' in chap_title:
break
del_index += 1
# 过滤章节下标
print(del_index)
# 过滤章节,从第一章开始
tar_dir_href_list = tar_dir_href[del_index:]
tar_len = len(tar_dir_href_list)
print('过滤后章节总数量:', tar_len) # 目录容器
mulu_dict = {}
# 章节标题,列表
mulu_dict['chap_title'] = []
# 章节url,列表
mulu_dict['chap_url'] = []
# 是否完成标志: 0-未完成,1-已完成,列表
mulu_dict['flag'] = []
# 循环读取章节
for dir_href in tar_dir_href_list:
# 章节标题
chap_title = dir_href.text
print(chap_title)
mulu_dict['chap_title'].append(chap_title)
# 章节url
chap_url = req_dict['novel_url'] + dir_href['href']
print(chap_url)
mulu_dict['chap_url'].append(chap_url)
mulu_dict['flag'].append('0')
# 转换为json字符串
json_str = json.dumps(mulu_dict)
json_name = req_dict['novel_name'] + '.json'
# 写入json文件
with open(json_name, 'w', encoding="utf-8") as json_file:
json_file.write(json_str)
# 返回容器
return [1, '000000', '爬取小说目录成功', [None]] except Exception as e:
print("爬取小说目录异常," + str(e))
return [0, '999999', "爬取小说目录异常," + str(e), [None]] def spider_novel_content(req_dict):
'''
@方法名称: 爬取小说章节明细内容
@中文注释: 读取章节列表json文件,爬取小说章节明细内容,保存到文本文件
@入参:
@param req_dict dict 请求容器
@出参:
@返回状态:
@return 0 失败或异常
@return 1 成功
@返回错误码
@返回错误信息
@param rsp_dict dict 响应容器
@作 者: PandaCode辉
@创建时间: 2023-09-21
@使用范例: spider_novel_content(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'
# 在列表中查找指定元素的下标,未完成标志下标
flag_index = mulu_dict['flag'].index('0')
print(flag_index)
# 未完成标志下标为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) print('打开浏览器驱动')
open_driver()
# 循环读取章节
for i in range(flag_index, chap_len):
# 章节标题
# chap_title = mulu_dict['chap_title'][i]
print('i : ', i)
# # 写入文件,章节标题
# fo.write(chap_title + "\r\n")
# 章节url
chap_url = mulu_dict['chap_url'][i]
# 章节分页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)) # 章节标题
chap_title = chap_soup.select(req_dict['chap_title'])[0].text
print(chap_title)
# 写入文件,章节标题
fo.write("\n" + chap_title + "\n")
# 章节内容
chap_content = chap_soup.select(req_dict['chap_content'])[0].text
chap_content = chap_content.replace(' ', '\n').replace(' ', '\n')
# print(chap_content)
# 写入文件,章节内容
fo.write(chap_content + "\n") # 分页列表大于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)
# 等待3秒启动完成
driver.implicitly_wait(3)
print("等待3秒启动完成")
# 根据url地址获取网页信息
chap_rst = get_html_by_webdriver(chap_url_page)
if chap_rst[0] != 1:
# 跳出循环爬取
break
chap_html_str = chap_rst[3][0] # 然后用BeautifulSoup解析html格式工具,简单的获取目标元素
chap_soup_page = BeautifulSoup(chap_html_str, "html.parser")
# 章节内容
chap_content_page = chap_soup_page.select(req_dict['chap_content'])[0].text
chap_content_page = chap_content_page.replace(' ', '\n').replace(' ', '\n')
# print(chap_content_page)
# 写入文件,章节内容
fo.write(chap_content_page + "\n")
# 爬取明细章节内容成功后,更新对应标志为-1-已完成
mulu_dict['flag'][i] = '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]] # 主方法
if __name__ == '__main__':
req_dict = {}
'''可变参数,小说名称和对应目录页面url地址'''
# 小说名称
req_dict['novel_name'] = '清末的法师'
# 目录页面地址,第1页
req_dict['mulu_url'] = 'https://www.bq0.net/1bqg/898531870/' '''下面参数不用变,一个官网一个特定参数配置'''
# 官网首页
req_dict['novel_url'] = 'https://www.bq0.net/'
# 章节目录定位
req_dict['tar_dir_href'] = "div.box_con>dl>dd>a"
# 章节标题定位
req_dict['chap_title'] = 'div.bookname > h1'
# 章节明细内容定位
req_dict['chap_content'] = 'div#content'
# 爬取小说目录
# spider_novel_mulu(req_dict)
# 爬取小说内容
spider_novel_content(req_dict)
第四步:运行测试效果
-------------------------------------------end---------------------------------------
selenium自动化测试-获取动态页面小说的更多相关文章
- selenium 操作 获取动态页面数据
# selenium from selenium import webdriver import time driver_path = r"G:\Crawler and Data\chrom ...
- Selenium 自动化测试中对页面元素的value比较验证 java语言
源代码: public boolean verifyText(String elementName, String expectedText) {String actualText = getValu ...
- Python+Selenium 自动化测试获取测试报告内容并发送邮件
这里封装一个send_mail()方法,用于测试完成后读取测试报告内容,并将测试结果通过邮件发送到接收人 # coding: utf-8 import smtplib from email.mime. ...
- Python+Selenium爬取动态加载页面(2)
注: 上一篇<Python+Selenium爬取动态加载页面(1)>讲了基本地如何获取动态页面的数据,这里再讲一个稍微复杂一点的数据获取全国水雨情网.数据的获取过程跟人手动获取过程类似,所 ...
- Python+Selenium爬取动态加载页面(1)
注: 最近有一小任务,需要收集水质和水雨信息,找了两个网站:国家地表水水质自动监测实时数据发布系统和全国水雨情网.由于这两个网站的数据都是动态加载出来的,所以我用了Selenium来完成我的数据获取. ...
- 基于selenium+phantomJS的动态网站全站爬取
由于需要在公司的内网进行神经网络建模试验(https://www.cnblogs.com/NosenLiu/articles/9463886.html),为了更方便的在内网环境下快速的查阅资料,构建深 ...
- 爬虫进阶之Selenium和chromedriver,动态网页(Ajax)数据抓取
什么是Ajax: Ajax(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意 ...
- selenium抓取动态网页数据
1.selenium抓取动态网页数据基础介绍 1.1 什么是AJAX AJAX(Asynchronouse JavaScript And XML:异步JavaScript和XML)通过在后台与服务器进 ...
- Selenium获取动态图片验证码
Selenium获取动态图片验证码 关于图片验证码的文章,我想大家都有一定的了解了. 在我们做UI自动化的时候,经常会遇到图片验证码的问题. 当开发不给咱们提供万能验证码,或者测试第三方网站比如知乎的 ...
- nodejs之获取客户端真实的ip地址+动态页面中引用静态路径下的文件及图片等内容
1.nodejs获取客户端真实的IP地址: 在一般的管理网站中,尝尝会需要将用户的一些操作记录下来,并记住是哪个用户进行操作的,这时需要用户的ip地址,但是往往当这些应用部署在服务器上后,都使用了ng ...
随机推荐
- Qt数据库应用1-数据导入导出csv
一.前言 在经历过大大小小十几个甚至几十个纯QtWidget项目后,涉及到数据库相关的项目,几乎都有一个需求,将少量的信息数据比如设备信息.防区信息等,导出到文件保存好,然后用户可以打开该表格进行编辑 ...
- AOP-Redis缓存
我没有单独使用过Redis,细节我可能解释不到位.该文章是采用依赖注入实现AOP-Redis缓存功能的 . 之前有写实现Memory缓存的.异曲同工之妙. 使用Redis离不开安装get包:Stack ...
- IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!
[来源申明]本文引用了微信公众号"鲜枣课堂"的<坐高铁手机没信号?原因远比你想的要复杂!>文章内容.为了更好的内容呈现,本文在引用和收录时内容有改动,转载时请注明原文来 ...
- 揭秘企业微信是如何支持超大规模IM组织架构的——技术解读四维关系链
本文由序员先生分享,原题"技术解读企业微信之四维关系链",本文有修订和改动. 1.引言 3年疫情后的中国社会,最大的永久性变化之一,就是大多数的企业.教育机构或者政务机构,都用上了 ...
- [转载] ABP框架理论学习之后台工作(Jobs)和后台工作者(Workers)
介绍 ABP提供了后台工作和后台工作者,它们会在应用程序的后台线程中执行一些任务. 后台工作 后台工作以队列和持续的方式在后台给一些即将被执行的任务排队.你可能因为某些原因需要后台工作,比如: 执行长 ...
- java-文件输入输出处理
--------------------------------------------------- 1.File类 File类是IO包中唯一代表磁盘文件本身的对象,File类定义了一些与平台无关的 ...
- Word文档转换成Html格式
CentOS 下安装 OpenOffice4.0 一.更新服务器 yum源 [root@APP2 /]# yum clean all [root@APP2 /]# yum makecache [roo ...
- code-generate(一个通用的代码生成工具)开源项目介绍
code-generate是一个通用的代码生成工具,支持从各种元数据,通过定义模板生成需要的代码,减少低级重复的编码工作.目前支持通过数据库元数据生成业务对象.数据访问对象等. 项目地址 gitee: ...
- flutter如何搭建android环境
1.电脑上按安装sdk 首先配置Java的JDK 配好后,输入java 出现内容说明安装成功 然后在输入javac 出现内容说明jre安装成功 2.电脑上安装android Studio 安卓下载地址 ...
- lagrange 插值做题记录
插值在OI中的应用 - Grice - 博客园 lagrange 插值笔记 - 洛谷专栏 P5850 calc加强版 - 洛谷 Problem - F - Codeforces 2025oifc202 ...