网页上异地加密数据的python爬虫
这里特别感谢钟思哲大佬帮我找到了问题并帮助解决
要搞python大作业
想从https://www.endata.com.cn/BoxOffice/BO/Year/index.html爬一个年度票房的数据出来
我参考了bilibili上的视频https://www.bilibili.com/video/BV1SJ411s7w5?
上面说的在网页上右击选择检查
之后右侧出现这个网页源码调试界面
对照着应该是从这个table中获取数据对吧
但是在这个地方遇到了问题
import requests
from bs4 import BeautifulSoup
proxies = {
"http" : "http://108.108.108.108:8899" # 代理ip
}
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
headers = {
'User-Agent' : user_agent }
#这个是一开始怀疑这个网站有反爬虫的设置 看了csdn上几篇关于应对反爬虫策略的文章 说是要模拟浏览器访问的过程 所以多设置了这些属性
#但是对这个project来说问题不在这里
text= requests.get(url="https://www.endata.com.cn/BoxOffice/BO/Year/index.html",).text
main_page= BeautifulSoup(text,"html.parser")
table = main_page.find("table",attrs={
"class":"bo-table img-table"})
print(table)
# 找的是一堆标签
f= open("电影票房.csv",mode="a")
div=table.find_all("div",attrs={
"class":"hb"})
ps=div.find_all("p")
for p in ps:
print(p.text)
python爬出来说<table里面是空的
我一开始怀疑这个网站有反爬虫的设置
看了csdn上几篇关于应对反爬虫策略的文章,说是要模拟浏览器访问的过程,所以在requests的get()里面多设置了这些属性
但是对这个project来说问题不在这里
首先我之前点的那个检查相当于是页面已经加载出来了之后的代码,但是并不是网页的源代码
网页源代码是这个样子的
可以看到这里面并没有上图的那个table和里面的tr什么的
<script>
function SetOption_Date(){
for(var t="",a=(new Date).getFullYear();2008<=a;a--)t+='<option value="'+a+'">'+a+"年</option>";$("#OptionDate").html(t).on("change",function(){
GetData_TableList()}).change()}
function GetData_TableList({
$Common.Popup.LoadingShow("WrapInfo"),$Common.Ajax.PostAPI("BoxOffice_GetYearInfoData","year="+$("#OptionDate option:selected").val(),function(t){
$Common.Popup.LoadingHide("WrapInfo"),t&&t.Table&&0<t.Table.length?$Common.Data.InitTemplate("TP_TableList",t.Table,function(t){
$("#TableList").html(t)}):$("#TableList").html('<p class="tac noData">暂无数据,请稍后再试!</p>')},function(t){
$Common.Popup.LoadingHide("WrapInfo"),$("#TableList").html('<p class="tac noData">暂无数据,请稍后再试!</p>')})}$(function(){
SetOption_Date()})
</script>
可以看出这里是写了一个请求,就是打开网页后的第二时间再去请求访问一个数据(数据没有存放在网页上),所以我们去看它访问的data是从哪里来的,然后去get那个data就可以了
但是问题又来了
打开里面XHR文件发现居然数据是加密的
如何加密一定就在那些JS文件中
先看了一下call stack来判断明文密文可能会在哪里
就是说,如果某个函数里面已经是明文了,那么就不用去这个函数里面call的下一级函数里面找加密的方法了,因为之后都是明文了,要去上一级找。
最终我们找到了这个加密肯定在蓝色的部分,于是我们再去寻找shell是如何定义的就可以解密。
之后在console里面进行了操作 搜索到了这个shell在哪里
点击那个蓝色的webDES.min.js?v=1.0.0:1出现了
this[_0x2246('0x257', 'nArV')] = function(_0xa0c834) {
var _0x51eedc = {
'pKENi': function _0x2f627(_0x5b6f5a, _0x440924) {
return _0x5b6f5a === _0x440924;
},
'wnfPa': 'ZGz',
'VMmle': '7|1|8|9|5|2|3|6|0|4',
'GKWFf': function _0x1a4e13(_0x40cfde, _0x16f3c2) {
return _0x40cfde == _0x16f3c2;
},
'MUPgQ': function _0x342f0d(_0x19038b, _0x4004d6) {
return _0x19038b >= _0x4004d6;
},
'hLXma': function _0x55adaf(_0x45a871, _0x161bdf) {
return _0x45a871 + _0x161bdf;
},
'JdOlO': function _0x13e00a(_0x5899a9, _0x4bb34d) {
return _0x5899a9 + _0x4bb34d;
},
'qrTpg': function _0x1198fb(_0x55b317, _0x22e1db, _0x1b091a) {
return _0x55b317(_0x22e1db, _0x1b091a);
},
'pdmMk': function _0xe2b022(_0x4af286, _0x4c2fd4) {
return _0x4af286 - _0x4c2fd4;
},
'xVKWW': function _0x1094a3(_0x5f3627, _0x2a0ac5, _0x3ad2e5) {
return _0x5f3627(_0x2a0ac5, _0x3ad2e5);
}
};
if (_0x51eedc[_0x2246('0x258', '@1Ws')](_0x2246('0x259', 'E&PI'), _0x51eedc['wnfPa'])) {
this['_append'](a);
return this[_0x2246('0x25a', 'GL3Q')]();
} else {
var _0x492a62 = _0x51eedc[_0x2246('0x25b', '&59Q')][_0x2246('0x25c', ')q#9')]('|')
, _0x356b01 = 0x0;
while (!![]) {
switch (_0x492a62[_0x356b01++]) {
case '0':
_0x554c90 = _grsa_JS[_0x2246('0x25d', 'E&PI')]['decrypt']({
'ciphertext': _grsa_JS['enc'][_0x2246('0x25e', 'sy^o')]['parse'](_0xa0c834)
}, _0x2cf8ae, {
'iv': _0x554c90,
'mode': _grsa_JS[_0x2246('0x16c', 'O^50')][_0x2246('0x25f', 'Who^')],
'padding': _grsa_JS[_0x2246('0x260', '7IfV')][_0x2246('0x261', 'E&PI')]
})[_0x2246('0x1c', 'yY#5')](_grsa_JS['enc'][_0x2246('0x262', ']2BX')]);
continue;
case '1':
if (_0x51eedc[_0x2246('0x263', 'Jsmq')](null, _0xa0c834) || _0x51eedc[_0x2246('0x264', '!2eC')](0x10, _0xa0c834['length']))
return _0xa0c834;
continue;
case '2':
_0xa0c834 = _0x9843d3(_0xa0c834, _0x2cf8ae, 0x8);
continue;
case '3':
_0x2cf8ae = _grsa_JS[_0x2246('0x265', 'RQ2o')][_0x2246('0x266', '3j7z')][_0x2246('0x267', 'RQ2o')](_0x554c90);
continue;
case '4':
return _0x554c90[_0x2246('0x268', 'cs*4')](0x0, _0x51eedc[_0x2246('0x269', 'MVsm')](_0x554c90[_0x2246('0x26a', '0J6f')]('}'), 0x1));
case '5':
_0x554c90 = _0xa0c834[_0x2246('0x26b', 'UwHa')](_0x2cf8ae, 0x8);
continue;
case '6':
_0x554c90 = _grsa_JS[_0x2246('0x26c', '4VZ$')]['Utf8']['parse'](_0x554c90);
continue;
case '7':
if (!navigator || !navigator[_0x2246('0x26d', '0I#o')])
return '';
continue;
case '8':
var _0x554c90 = _0x51eedc[_0x2246('0x26e', 'Yb4P')](_0x51eedc[_0x2246('0x26f', 'BQ5p')](parseInt, _0xa0c834[_0x51eedc[_0x2246('0x270', 'Z2VK')](_0xa0c834['length'], 0x1)], 0x10), 0x9)
, _0x2cf8ae = _0x51eedc[_0x2246('0x271', 'yY#5')](parseInt, _0xa0c834[_0x554c90], 0x10);
continue;
case '9':
_0xa0c834 = _0x9843d3(_0xa0c834, _0x554c90, 0x1);
continue;
}
break;
}
}
}
;
}
, webInstace = new webDES();
大家感受一下,这个是加了混淆之后的代码(为了让代码可读性更加差)
然而由于网络上没有找到特别好的解析出反混淆的代码的小程序(甚至大佬还尝试了用一个新的变量来代替这一堆,但是后来还是放弃了…)
—————————————————————————————————
下面是方法二(最终成功了)
在你的Py程序中添加无头浏览器模块
提交网页地址给无头浏览器模块
无头浏览器执行JS,等待加载完成
无头浏览器返回全部网页文本给你的Py程序(这时返回的就是加载后的网页代码)
这种方法比较简单 但是电脑会比较累
参考https://www.cnblogs.com/linxiyue/p/10215912.html
“一般的的静态HTML页面可以使用requests等库直接抓取,但还有一部分比较复杂的动态页面,这些页面的DOM是动态生成的,有些还需要用户与其点击互动,这些页面只能使用真实的浏览器引擎动态解析,Selenium和Chrome Headless可以很好的达到这种目的。”
附上代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import time
chrome_options = webdriver.ChromeOptions()
# 使用headless无界面浏览器模式
chrome_options.add_argument('--headless') #增加无界面选项
chrome_options.add_argument('--disable-gpu') #如果不加这个选项,有时定位会出现问题
chrome_drivers = "/Users/VictoriaShaw/chromedriver"
# 启动浏览器,获取网页源代码
browser = webdriver.Chrome(options=chrome_options, executable_path=chrome_drivers)
mainUrl = "https://www.endata.com.cn/BoxOffice/BO/Year/index.html"
browser.get(mainUrl)
#有些图片需要滚动到才可以加载出来的时候需要这个scroll
# 本project中想要获取的是里面的数据 不需要图片 以下4行代码可以不要
for i in range(1, 11):
browser.execute_script(
"window.scrollTo(0, document.body.scrollHeight/10*%s);" % i
)
time.sleep(0.5) #取决于原页面的加载速度 如果这个sleep里面的时间小雨实际加载出来的时间,那么得到的数据就会不完整
data = browser.page_source
with open("test.out.html", "w") as f:
f.write(str(data))
之后就得到了一个html文件
里面的代码页面加载后的代码
查看一下果然里面的table是有tr和里面的数据的
}</script><section class="box-office-bg navgation"><div class