Javascript动态生成的页面信息爬取和openpyxl包FAQ小记
最近,笔者在使用Requests模拟浏览器发送Post请求时,发现程序返回的html与浏览器F12观察到的略有不同,经过观察返回的response.text,cookies确认有效,因为我们可以看到返回的登陆信息。然而部分字段的值依然显示为空。
下图是浏览器F12抓包看到的界面:

由于笔者在查看第一个接口请求时,观察浏览器捕获到的Response(html文件)跟页面展示的信息一致,就单纯以为只要用requests库构造这个请求即可。然而实际上第一个表单只是返回了前台页面的框架,很多数据都是通过script、XHR等格式的请求返回数据后,再动态加载到基础框架页面的。
那么直接挑重点,请求下面关键的list.do等xhr信息可以吗?
此例中是不可以的,整个前台网页的内容填充是分模块的,后台每个js文件或者json返回都只决定了页面的一部分信息,这就导致要完整获得页面的信息就需要模拟多个请求。更关键的是,前端页面的部分信息是结合后台的返回的json文件经过一定规律的运算后,才返回的最终结果。如果不能定位到页面中的值后台的运算函数,我们无法模拟后台服务器行为构造同样的函数。
这种靠多个JavaScript文件渲染后生成的网页,直接用requests库来爬取就显得难度较大。
此时通过查阅资料,发现有两种方法来解决JavaScript动态生成页面信息的爬取:(参考博客:https://www.cnblogs.com/taolusi/p/9282565.html)
1.1 用dryscrape库动态抓取页面
js脚本是通过浏览器来执行并返回信息的,所以,抓取js执行后的页面,一个最直接的方式就是用python模拟浏览器的行为。WebKit 是一个开源的浏览器引擎,python提供了许多库可以调用这个引擎,dryscrape便是其中之一,它调用webkit引擎来处理包含js等的网页!ps:该方法由于其底层操作逻辑(python调用 webkit请求页面,而且等页面加载完,载入js文件,让js执行,将执行后的页面返回),导致实际过程偏慢。
import dryscrape
# 使用dryscrape库 动态抓取页面
def get_url_dynamic(url):
session_req=dryscrape.Session()
session_req.visit(url) #请求页面
response=session_req.body() #网页的文本
#print(response)
return response
get_text_line(get_url_dynamic(url)) #将输出一条文本
1.2 使用selenium来完成动态页面的爬取
selenium是一个web测试框架,它允许调用本地的浏览器引擎发送网页请求,所以,它同样可以实现抓取页面的要求。
这也是笔者之前大部分文章中推荐的的框架,所谓“可见即可爬”,只可惜效率较requests后台请求的方式,依旧要慢不少。如果能结合Chrome浏览器的headless模式,静默爬取,则能稍微提升一点效率。开启headless模式代码示例:
from selenium import webdriver
option = webdriver.ChromeOptions()
option.add_argument('headless')
driver = webdriver.Chrome(chrome_options=option)
driver.get(url) #访问网址
page_content=driver.page_source #获取js选然后的页面源码
经过上诉操作后,我们就可以拿到页面最终的源码。
但是实际使用中,selenium还有一个问题,就是“可见方可爬”,有些在源码中明明能看到的页面元素,如果前台显示页面,需要点击才会出现,则我们也要模拟浏览器行为,利用click()方法,点击才能拿到相关节点的数据。如:

假如页面停留在“基础信息”界面,如果想取到“审批信息”tab页的信息,则需要模拟点击“审批信息”,这多少会降低爬取效率。
此时,建议直接用BeautifulSoup包来解析html文件,再配合万能的正则表达式RE直接取,不到迫不得已尽量不去模拟浏览器点击行为(除非页面源码中没有,需要点击触发js动态返回信息的情况)。
下面是我实际工作中结合源码和bs4(BeautifulSoup),re表达式来爬取特定字段的示例:
whole_text=driver.page_source #提取加载后的源码
soup=BeautifulSoup(whole_text,"lxml")
haf=str(soup.select('script')[6]) #得到haf字段,再进行后续提取
flowHiComments=re.search('.*?flowHiComments\":(.*?),\"flowHiNodeIds.*?',haf,re.S)
applyerId=soup.find(id="afPersonId")['value'] #根据id查找
applyerName=re.search('.*?applyerName\":\"(.*?)\".*?',haf,re.S).group(1) #根据re表达式的group方法提取字符串特定字段
flowHiComments=json.loads(flowHiComments.group(1)) #得到页面评论信息
with open('.\\CommentFlow\\%s_%s.txt'%(bpmDefName,afFormNumber),'w',encoding="utf-8") as txt: #将flowHiComments保存为本地txt文件,并对文件进行格式化
json.dump(flowHiComments,txt,ensure_ascii = False,indent=4)
当拿到特定字段后,就需要逐条对信息进行存储,譬如将信息保存同本地excel文件,这时要用到openpyxl文件。
openpyxl文件对excel新格式的支持比较友好,实际使用中依旧有些地方需要注意:
1.openpyxl默认提供返回excel最后一行(列)的索引号:
利用ws.mas_row和 ws.max_column 两个原生方法即可,但是倘若我们想要读到任意一列的最后一行行号呢?ws.max_row就显得不那么灵活了。

如果要取到A列所有元素到内存,则可以使用的示例代码如下:
name=[]
while True:
if sheet.cell(num,1).value ==None:
break
name.append(sheet.cell(num,1).value) #名称
num+=1
B列的取值,同理可得。
2.我们习惯用ws.append()方法按照行来追加数据到表格中,实测,每次内容追加都是从第二行开始(是否考虑第一行为标题行),倘若我们希望程序执行时动态添加标题行呢?
笔者实测了下:
from openpyxl import load_workbook
wb= load_workbook('test2.xlsx')
#wb.active =1
sheet=wb["Sheet1"]
row = [1 ,2, 3, 4, 5]
sheet.append(row) wb.save('test2.xlsx')
结果执行完后excel端生成的数据是从第二行开始的:

这显然有时无法满足我们的要求,关于第一行如果要传值就不建议使用原生的append方法了,可行的建议如下:
navigation=[]
if ws.cell(1,1).value ==None:
navigation=["名称","单号","业务描述","申请者","申请者编号","代码","备注"]
for m in range(len(navigation)):
ws.cell(1,m+1).value=navigation[m]
上述代码中的navigation列表每个元素当然也能传入爬虫捕获到的字段值(变量),非常灵活!
爬虫过程中总是遇到这样那样的问题,归纳和总结加上前人积累的经验 就显得尤为重要,避免重复踩坑!
Javascript动态生成的页面信息爬取和openpyxl包FAQ小记的更多相关文章
- 2)JS动态生成HTML元素的爬取
2)JS动态生成HTML元素的爬取 import java.util.List; import org.openqa.selenium.By; import org.openqa.selenium.W ...
- 豆瓣电影信息爬取(json)
豆瓣电影信息爬取(json) # a = "hello world" # 字符串数据类型# b = {"name":"python"} # ...
- 爬虫开发6.selenuim和phantonJs处理网页动态加载数据的爬取
selenuim和phantonJs处理网页动态加载数据的爬取阅读量: 1203 动态数据加载处理 一.图片懒加载 什么是图片懒加载? 案例分析:抓取站长素材http://sc.chinaz.com/ ...
- python requests库网页爬取小实例:亚马逊商品页面的爬取
由于直接通过requests.get()方法去爬取网页,它的头部信息的user-agent显示的是python-requests/2.21.0,所以亚马逊网站可能会拒绝访问.所以我们要更改访问的头部信 ...
- 爬虫--selenuim和phantonJs处理网页动态加载数据的爬取
1.谷歌浏览器的使用 下载谷歌浏览器 安装谷歌访问助手 终于用上谷歌浏览器了.....激动 问题:处理页面动态加载数据的爬取 -1.selenium -2.phantomJs 1.selenium 二 ...
- 安居客scrapy房产信息爬取到数据可视化(下)-可视化代码
接上篇:安居客scrapy房产信息爬取到数据可视化(下)-可视化代码,可视化的实现~ 先看看保存的数据吧~ 本人之前都是习惯把爬到的数据保存到本地json文件, 这次保存到数据库后发现使用mongod ...
- (五)selenuim和phantonJs处理网页动态加载数据的爬取
selenuim和phantonJs处理网页动态加载数据的爬取 一 图片懒加载 自己理解------就是在打开一个页面的时候,图片数量特别多,图片加载会增加服务器的压力,所以我们在这个时候,就会用到- ...
- 网易新闻页面信息抓取(htmlagilitypack搭配scrapysharp)
转自原文 网易新闻页面信息抓取(htmlagilitypack搭配scrapysharp) 最近在弄网页爬虫这方面的,上网看到关于htmlagilitypack搭配scrapysharp的文章,于是决 ...
- 根据html页面模板动态生成html页面(c#类)
本文转载自:http://www.cnblogs.com/yuanbao/archive/2008/01/06/1027985.html点击打开链接 一直以为动态生成静态页面不好做,昨天在网上找了下, ...
随机推荐
- Python学习笔记二
---恢复内容开始--- 一. python几种数据类型的比较. 从以下几个方面比较: 1. 是否可变. 不可变类型:变量的值可以发生变化,id也变了,相当于创建了一个新的对象,所以一修改值,id就变 ...
- Jmeter性能测试之基础知识(一)
1. 官网下载Jmeter: 点这里, 下载完成解压即可 2. 启动: 进入解压后的bin目录, Windows点击jmeter.bat, Linux执行jmeter 3. 添加线程组(user) : ...
- 开启Golang编程第一章
Go is an open source programming language that makes it easy to build simple,reliable, and effcient ...
- 解决问题:CA_ERROR证书出错,请登录微信支付商户平台下载证书-企业付款到零钱接口(原创)
这几天用到了微信企业付款到零钱这个接口,结果出现了报错:CA_ERROR, 该接口的API说明和报错提示说明:https://pay.weixin.qq.com/wiki/doc/api/tools/ ...
- 无法执行该VI,必须使用LabVIEW完整版开发系统才可以解决该错误
该错误99%是因为你在某个vi中使用了外部系统组件,比如api,.net组件,ActiveX组件,com组件,所有不是Labview原生的接口,在你打包后,在其他没有安装这些组件的电脑上运行,就会出现 ...
- 20172328 2018-2019《Java软件结构与数据结构》第六周学习总结
20172328 2018-2019<Java软件结构与数据结构>第六周学习总结 概述 Generalization 本周学习了第十章:非线性集合与数据结构--树.主要讨论了树的使用和实现 ...
- YII2 console中引用其他模块(子项目)的model时出现model找不到命名空间的问题解决
YII2 console中写定时任务, 想使用其他模块的model, 在 console的yii.php 入口文件中引入其他模块的配置文件, 否者会出现model等命名空间找不到的问题. 还有, 命名 ...
- css 元素溢出
css元素溢出: 当子元素的尺寸超过父元素的尺寸时,需要设置父元素显示溢出的子元素的方式,设置的方法是通过overflow属性来设置. overflow的设置项: (1)visible 默认值 内容不 ...
- 小甲鱼Python第十九讲课后习题
笔记: 1.内嵌函数:函数内部新创建另一个函数 2.闭包:函数式编程的重要语法,如果在一个内部函数里,对外部作用域(但不是在全局作用域的变量)进行引用,那么内部函数就会被认为是闭包. 3.nonloc ...
- React_基本原理_ajax
React 基本原理 初始化显示界面 创建虚拟DOM树 渲染到 原生 DOM 树 绘制界面显示 更新界面 setState() 更新状态机 重新创建虚拟 DOM 树 新/旧树比较差异 (执行一次 DO ...