1. 程式人生 > >應對js反爬蟲的嘗試,爬取中國人民銀行

應對js反爬蟲的嘗試,爬取中國人民銀行

應對js反爬蟲的嘗試,爬取中國人民銀行

在 - 簡書-爬蟲資料分析學習交流 - 微信群裡有位朋友Jacky提到爬取中國銀行遇到的問題,一時興起便做了嘗試。


  • 首先還原問題,我們禁用js,在chrome瀏覽器中新建標籤頁,F12 > F1 >開啟設定在右下角找到禁用js並勾選


  • 開啟中國人民銀行條法司網頁發現如下的頁面顯示
  • 然後F12關閉開發者控制檯,重新整理頁面,顯示正常


  • 利用chrome外掛,EditThisCookie,在控制檯中檢視cookie如下,同時禁用js再次開啟網頁卻發現顯示正常,而清空cookie(禁用js)後開啟又出現問題顯示。
  • 這是因為該網頁首先傳給你的html檔案中包含cookie設定和動態跳轉網址的js程式碼,js程式碼執行後會自動設定cookie並跳轉連結,到達正常頁面。
  • 我們檢視問題頁面的原始碼,Ctrl-U


    Paste_Image.png
  • 原始碼很亂,以我的菜雞水平根本看不出來什麼東西,這時需要優秀工具的幫助,http://jsbeautifier.org/ 是一款優秀js程式碼美化和解析工具,我們將程式碼放上去解析,終端curl網頁得到的js程式碼和解析後的程式碼對比鮮明
  • 與一般的程式碼美化工具比較(下圖),不僅格式化了程式碼,並且可讀化了程式碼,這樣以我的水平就可以分析程式碼了。


  • 首先兩次請求該網址,將兩次美化後的程式碼進行對比,我們可以看到不僅在js全域性變數上有改變,在其中一個加密函式裡也有小改動。



  • 某一個請求裡的js程式碼,留存參考,閱讀可先跳過:
var dynamicurl = "/L3RpYW9mYXNpLzE0NDk0MS8xNDQ5NTcvaW5kZXguaHRtbA==";
var wzwschallenge = "RANDOMSTR14925";
var wzwschallengex = "STRRANDOM14925";
var template = 4;
var encoderchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function KTKY2RBD9NHPBCIHV9ZMEQQDARSLVFDU(str) {
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = “”;
while (i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if (i == len) {
out += encoderchars.charAt(c1 >> 2);
out += encoderchars.charAt((c1 & 0x3) << 4);
out += “==”;
break;
}
c2 = str.charCodeAt(i++);
if (i == len) {
out += encoderchars.charAt(c1 >> 2);
out += encoderchars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
out += encoderchars.charAt((c2 & 0xf) << 2);
out += “=”;
break;
}
c3 = str.charCodeAt(i++);
out += encoderchars.charAt(c1 >> 2);
out += encoderchars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
out += encoderchars.charAt(((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6));
out += encoderchars.charAt(c3 & 0x3f);
}
return out;
}

function findDimensions() {
var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
var h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
if (w * h <= 120000) {
return true;
}
var x = window.screenX;
var y = window.screenY;
if (x + w <= 0 || y + h <= 0 || x >= window.screen.width || y >= window.screen.height) {
return true;
}
return false;
}

function QWERTASDFGXYSF() {
var tmp = wzwschallenge + wzwschallengex;
var hash = 0;
var i = 0;
for (i = 0; i < tmp.length; i++) {
hash += tmp.charCodeAt(i);
}
hash *= 11;
hash += 111111;
return “WZWS_CONFIRM_PREFIX_LABEL4” + hash;
}

function HXXTTKKLLPPP5() {
if (findDimensions()) {} else {
var cookieString = “”;
cookieString = “wzwstemplate=” + KTKY2RBD9NHPBCIHV9ZMEQQDARSLVFDU(template.toString()) + “; path=/”;
document.cookie = cookieString;
var confirm = QWERTASDFGXYSF();
cookieString = “wzwschallenge=” + KTKY2RBD9NHPBCIHV9ZMEQQDARSLVFDU(confirm.toString()) + “; path=/”;
document.cookie = cookieString;
window.location = dynamicurl;
}
}
HXXTTKKLLPPP5();

  • 這種程度的js程式碼(美化後)並不難理解,很明顯可以看出最後的函式呼叫中利用document.cookie設定了兩個cookie,並利用window.location設定了跳轉網址,靜下心去分析也能用python寫出相應的加密程式,用正則取配到變數,生成我們想要的資訊,但是有沒有更快的方法呢。這時我們又有一個強大的工具,Js2Py,利用它我們可以解析js程式碼變為python中的可執行程式碼。如下官方簡單示例:
  • 下面的思路就清晰了,先利用js美化工具的python庫jsbeautifier(pip安裝)美化程式碼,然後不管js程式碼中關於dom操作的內容(如window.xx),取出js全域性變數和加密函式,利用js2py生成可執行的python函式,以js程式碼中的主幹邏輯在python裡執行獲得cookies,在requests.session中更新cookies並訪問js變數中的動態網址,就可以成功到達內容頁,開始爬取解析了。
  • 以下為python程式碼,可以看到最後成功驗證我們爬取到了有效資訊。
import requests
import re
import jsbeautifier
import js2py

host_url = http://www.pbc.gov.cn/
dest_url = http://www.pbc.gov.cn/tiaofasi/144941/144957/index.html
# 利用session儲存cookie資訊,第一次請求會設定cookie類似{‘wzwsconfirm’: ‘ab3039756ba3ee041f7e68f634d28882’, ‘wzwsvtime’: ‘1488938461’},與js解析得到的cookie合起來才能通過驗證
r = requests.session()
content = r.get(dest_url).content
# 獲取頁面指令碼內容
re_script = re.search(r’<script type=“text/javascript”>(?P<script>.*)</script>’, content.decode(‘utf-8’), flags=re.DOTALL)
# 用點匹配所有字元,用(?P<name>…)獲取:https://docs.python.org/3/howto/regex.html#regex-howto
# cheatsheet:https://github.com/tartley/python-regex-cheatsheet/blob/master/cheatsheet.rst
script = re_script.group(‘script’)
script = script.replace(’\r\n’, ‘’)
# 在美化之前,去掉\r\n之類的字元才有更好的效果
res = jsbeautifier.beautify(script)
# 美化並一定程度解析js程式碼:https://github.com/beautify-web/js-beautify
with open(‘x.js’,‘w’) as f:
f.write(res)
# 寫入文件進行檢視分析

jscode_list = res.split(‘function’)
var_ = jscode_list[0]
var_list = var_.split(’\n’)
template_js = var_list[3] # 依順序獲取,亦可用正則
template_py = js2py.eval_js(template_js)
# 將所有全域性變數插入第一個函式變為區域性變數並計算
function1_js = ‘function’ + jscode_list[1]
position = function1_js.index(’{’) +1
function1_js = function1_js[:position]+ var_ +function1_js[position:]
function1_py = js2py.eval_js(function1_js)
cookie1 = function1_py(str(template_py)) # 結果類似’NA==’
# 儲存得到的第一個cookie
cookies = {}
cookies[‘wzwstemplate’] = cookie1
# 對第三個函式做類似操作
function3_js = ‘function’ + jscode_list[3]
position = function3_js.index(’{’) +1
function3_js = function3_js[:position]+ var_ +function3_js[position:]
function3_py = js2py.eval_js(function3_js)
middle_var = function3_py() # 是一個str變數,結果類似’WZWS_CONFIRM_PREFIX_LABEL4132209’
cookie2 = function1_py(middle_var)
cookies[‘wzwschallenge’] = cookie2
# 關於js程式碼中的document.cookie參見 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie
dynamicurl = js2py.eval_js(var_list[0])

# 利用新的cookie對提供的動態網址進行訪問即是我們要達到的內容頁面了
r.cookies.update(cookies)
content = r.get(host_url+dynamicurl).content

# 最後驗證是否爬取到有效資訊
if u’銀行卡清算機構管理辦法’ in content.decode(‘utf-8’):
print(‘success’)

原文:出自簡書,作者:無名之輩https://www.jianshu.com/p/f5854aed87c8?t=1489239069247