动态网页抓不了?JavaScript入门攻略已发送~
优采云 发布时间: 2022-06-17 20:48动态网页抓不了?JavaScript入门攻略已发送~
var carname="Volvo";
0 3
变量命名的规则
① 由字母、数字、下划线和 $ 组成,但是不能以数字开头,如:12asd 这个名字就会报错
② 不能是关键字或保留字,比如 var、for等
③ 严格区分大小写,就是说大写和小写都是不一样的变量
0 4
数据类型
JavaScript 的数据类型分两种,一种是简单数据类型,另一种是复杂数据类型。
示例:返回的类型是一个number;
<br /> var a = 123; //var是设置一个变量 alert('hello') //一个弹窗,可以判断是否为外部引入的 console.log(a) //console.log():是在浏览器的控制台上的输出 console.log(typeof a); //typeof 判断是属于什么类型<br />
需要注意:要严格区分大小写,否则便会出现报错。
0 5
介绍几个函数
(1)Number() 将数据转换成number类型,里面的参数便是你要转变类型的数据。<br />(2)toString() String() 两种方法将数据转换成字符串类型;区别String() 可以将null 转换成"null" toString() 返回的是undefined;<br />(3)Boolean() 将数据类型转换换成布尔类型;bool 返回两种数据类型,一个是true 一个是false。在将 Boolean 类型转 Number 时,true会转为 1, false 会转为 0,这个方法不支持将数字开头带有其它字符的字符串转为数值类型,如 “12df”。
2 Python执行JS代码的方式
Python执行JS代码的三种方式;
1
使用 js2py
基本操作示例:
import js2py<br /><br /># 执行单行js语句js2py.eval_js("console.log(abcd)")>>> abcd<br /># 执行js函数add = js2py.eval_js("function add(a, b) {return a + b};")print(add(1,2))>>> 3<br /># 另一种方式js = js2py.EvalJs({})js.execute("js语句")
在js代码中引入python对象或python代码
# 在js代码中引入python对象context = js2py.EvalJs({'python_sum': sum})context.eval('python_sum(new Array(1,4,2,7))')>>> 14<br /># 在js代码中加入python代码js_code = ''' var a = 10 function f(x) {return x*x}'''context.execute(js_code)context.f("14") 或 context.f(14)>>> 196
将js代码转为python模块,再使用import 导入
# 转换js文件js2py.translate_file('example.js', 'example.py')<br /># 现在可以导入example.pyfrom example import exampleexample.someFunction()<br /><br /><br /># 转换js代码js2py.translate_js('var $ = 5')>>> """from js2py.pyjs import *# setting scopevar = Scope( JS_BUILTINS )set_global_object(var)# Code follows:var.registers(['$'])var.put('$', Js(5.0))"""
不过py2js有时候在加载一些加密函数的时候效率低的可怜,大概是因为执行
机制的不同;
py2js直接调用的nodejs引擎不过这个库用的nodejs解析语法树转成py代码,性能挺低的,还不如直接用execjs调nodejs或自己封装子进程调用。
2
使用 execjs
import execjs<br />js_code = open('file.js',encoding='utf-8').read()ctx = execjs.compile(js_code)<br /># 第一个参数为ja代码中的函数名, 后面为函数对应的参数result = ctx.call('function_name', *args)
3
使用subprocess调用node子进程
import subprocess<br /># js文件最后必须有输出,我使用的是 console.logpro = subprocess.run("node abc.js", stdout=subprocess.PIPE)# 获得标准输出_token = pro.stdout# 转一下格式token = _token.decode().strip()
3 JS动态网页抓取方式
许多时候爬虫取到的页面仅仅是一个静态的页面,即网页的源代码,就像在浏览器上的“查看网页源代码”一样。
一些动态的东西如javascript脚本执行后所产生的信息是抓取不到的;
下面两种方案,可用来python爬取js执行后输出的信息。
① 用dryscrape库动态抓取页面
js脚本是通过浏览器来执行并返回信息的,所以,抓取js执行后的页面,一个最直接的方式就是用python模拟浏览器的行为。
WebKit 是一个开源的浏览器引擎,python提供了许多库可以调用这个引擎,dryscrape便是其中之一,它调用webkit引擎来处理包含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)) #将输出一条文本
这里对于其余包含js的网页也是适用的,虽然可以满足抓取动态页面的要求,
但缺点还是很明显的:慢!
但想想也合理,python调用 webkit请求页面,而且等页面加载完,载入js文件,让js执行,将执行后的页面返回,慢一点情理之中。
除外还有很多库可以调用 webkit:PythonWebkit,PyWebKitGit,Pygt(可以用它写个浏览器),pyjamas等等,也可以实现相同的功能。
② selenium web测试框架
selenium是一个web测试框架,允许调用本地的浏览器引擎发送网页请求,所以,它同样可以实现抓取页面的要求。
使用 selenium webdriver 可行,但会实时打开浏览器窗口。
def get_url_dynamic2(url): driver=webdriver.Firefox() #调用本地的火狐浏览器,Chrom 甚至 Ie 也可以的 driver.get(url) #请求页面,会打开一个浏览器窗口 html_text=driver.page_source driver.quit() #print html_text return html_text get_text_line(get_url_dynamic2(url)) #将输出一条文本
不失为一条临时的解决方案,与selenium类似的框架还有一个windmill,
感觉稍复杂一些,这里就暂且不赘述了。
4解析JS
我们爬虫每次只有一个请求,但是实际上很多请求又js连带发送,所以我们需要利用爬虫解析js去实现这些请求的发送。
网页中的参数来源主要有以下四种:
这里主要介绍一下解析js,破解加密方法或者生成参数值方法,python代码模拟实现这个方法, 从而得到我们需要的请求参数。
以微博登录为例:
当我们点击登录的时候都会发送一个login请求
登录表单中的参数并不一定都是我们需要的,可以通过对比多次请求中的参数,再加上一些经验和猜想,过滤掉固定参数或服务器自带参数和用户输入的参数。
这是剩下的就是js生成的数值或加密数值;
最终得到的值:
# 图片 picture id:pcid: yf-d0efa944bb243bddcf11906cda5a46dee9b8# 用户名:su: cXdlcnRxd3Jlnonce: 2SSH2A # 未知# 密码:sp: e121946ac9273faf9c63bc0fdc5d1f84e563a4064af16f635000e49cbb2976d73734b0a8c65a6537e2e728cd123e6a34a7723c940dd2aea902fb9e7c6196e3a15ec52607fd02d5e5a28e18254105358e897996f0b9057afe2d24b491bb12ba29db3265aef533c1b57905bf02c0cee0c546f4294b0cf73a553aa1f7faf9f835e5prelt: 148 # 未知
请求参数中的用户名和密码都是经过加密处理的,如果需要模拟登录,就需要找到这个加密的方法,利用它来为我们的数据进行加密。
1)找到所需的js
要找到加密方法,首先我们需要先找到登录所需的js代码,可以使用以下3种方式:
① 找事件;在页面检查目标元素,在开发工具的子窗口里选中Events Listeners, 找到click事件,点击定位到js代码。
② 找请求;在Network中点击列表界面的对应Initiator跳转至对应js界面;
③ 通过搜索参数名进行定位;
2)登录的js代码
3)在这个submit的方法上打断点
然后输入用户名密码,先不点登录,回到dev tool点击这个按钮启用调试。
4)然后再去点登录按钮, 这时候就可以开始调试;
5)逐步执行代码的同时观察我们输入的参数, 发生变化的地方即为加密方法
如下示例:
6)上图中的加密方式是base64, 我们可以使用代码来试一下
import base64<br />a = "aaaaaaaaaaaa" # 输入的用户名print(base64.b64encode(a.encode())) # 得到的加密结果:b'YWFhYWFhYWFhYWFh'# 如果用户名包含@等特殊符号, 需要先用parse.quote()进行转义
得到的加密结果与网页上js的执行结果一致;
5爬虫中JS反爬技术
爬虫中遇到的js反爬技术(重点)
0 1
JS写cookie
requests请求得到的网页是一对JS,跟浏览器打开看到的网页源码完全不一样。
这种情况,往往是浏览器运行这段JS生成一个(或多个)cookie再带着这个cookie做二次请求。
在浏览器(chrome、Firefox都可以)里可以看到这一过程,首先把Chrome浏览器保存的该网站的cookie删除。
按F12到Network窗口,把“preserve log”选中(Firefox是“Persist logs”),刷新网页,这样我们就可以看到历史的Network请求记录。
第一次打开“index.html”页面时返回的是521, 内容是一段JS代码;
第二次请求这个页面就得到了正常的HTML,查看两次请求的cookies,可以发现第二次请求时带上了一个cookie,而这个cookie并不是第一次请求时服务器发过来的,其实它就是JS生成的。
解决思路:研究那段JS,找到它生成cookie的算法,爬虫就可以解决这个问题。
0 2
JS加密ajax请求参数
抓某个网页里面的数据,发现网页源代码里面没有我们要的数据,麻烦之处在于数据往往是ajax请求得到的。
按F12打开Network窗口,刷新网页看看加载这个网页都下载了哪些URL,我们要的数据就在某个URL请求的结果里面。
这类URL在Chrome的Network里面的类型大多是XHR,通过观察它们的“Response”就可以发现我们要的数据。
我们可以把这个URL拷贝到地址栏,把那个参数随便改个字母,访问一下看看是不是能得到正确的结果,由此来验证它是否是很重要的加密参数。
解决思路:对于这样的加密参数,可以尝试通过debug JS来找到对应的JS加密算法,其中关键的是在Chrome里面设置“XHR/fetch Breakpoints”。
0 3
JS反调试(反debug)
前面我们都用到了Chrome 的F12去查看网页加载的过程,或者是调试JS的运行过程。
不过这种方法用多了,网站就加了反调试的策略,只有我们打开F12,就会暂停在一个“debugger”代码行,无论怎样都跳不出去。
不管我们点击多少次继续运行,它一直在这个“debugger”这里,每次都会多出一个VMxx的标签,观察“Call Stack”发现它好像陷入了一个函数的递归调用。
这个“debugger”让我们无法调试JS,但是关掉F12窗口,网页就正常加载了。
解决思路:“反-反调试”,通过“Call Stack”找到把我们带入死循环的函数,重新定义它。
JS的运行应该停止在设置的断点处,此时该函数尚未运行,我们在Console里面重新定义它,继续运行就可以跳过该陷阱。
0 4
JS发送鼠标点击事件
有些网站它的反爬都不是上面的方式,你从浏览器可以打开正常的页面,而在requests里面却被要求输入验证码或重定向其它网页。
可以试着从“Network”看看,比如下面这个Network流里面的信息:
认真看看后会发现,每点击页面的的链接,它都会做一个“cl.gif”的请求,它看上去是下载一个gif图片,然而并不是。
它请求时发送的参数非常多,而且这些参数都是当前页面的信息。比如包含了被点击的链接等等。
先来顺一下它的逻辑:
① JS会响应链接被点击的事件,在打开链接前,先访问cl.gif,把当前的信息发送给服务器,然后再打开被点击的链接。
② 服务器收到被点击链接的请求,会看看之前是不是已经通过cl.gif把对应信息发过来,如果发过来了就认为是合法的浏览器访问,给出正常的网页内容。
③ 因为requests没有鼠标事件响应就没有访问cl.gif的过程就直接访问链接,服务器就拒绝服务。
解决思路:在访问链接前先访问一下cl.gif即可,关键是要研究cl.gif后的参数,把这些参数都带上问题就不大了,这样就可以绕过这个反爬策略。
END
最后:
欢迎关注「Python新手快速入门」
每天5分钟,学习一个Python小Tip!助力你成为更优秀的Python学习者~