在抓取數據的時候每每能夠經過狀態碼來判斷返回結果,今天在抓取數據的時候碰到了之前沒有碰到過得狀態碼521,輸出它的爬取內容(text),發現是一些js代碼。一塊兒探討一下如何處理521狀態碼。python
用charles抓包的時候,發現瀏覽器對於同一網頁連續訪問了兩次,第一次的訪問狀態碼爲521,第二次爲200(正常訪問)。看來網頁加了反爬蟲機制,須要兩次訪問纔可返回正常網頁。瀏覽器
經過對比兩次請求,咱們發現第二次訪問帶了新的cookie值。再考慮上面程序對爬取結果的輸出爲js代碼,能夠考慮其操做過程爲:第一次訪問時服務器返回一段可動態生成cookie值的js代碼;瀏覽器運行js代碼生成cookie值,並帶cookie從新進行訪問;服務器被正常訪問,返回頁面信息,瀏覽器渲染加載。
弄清楚瀏覽器的執行過程後,咱們就能夠模擬其行爲經過python做網頁爬取。操做步驟以下:
-
用request.get(url)獲取js代碼服務器
-
執行函數eval()語句修改成return語句返回cookie值cookie
-
調用execjs執行js代碼得到cookie值函數
-
將cookie值轉化爲字典格式,用request.get(url, headers=headers)方法獲取獲得正確的網頁信息url
代碼以下:spa
def getResponse(): """ 獲取response :return: """ response = requests.get(startUrl, headers=headers) return responsedef getJslid(response): """ :param response: :return: """ cook = response.cookies return '; '.join(['='.join(item) for item in cook.items()])def getClearance(response): """ :return: """ txt = ''.join(re.findall('<script>(.*?)</script>', response.text)) func_return = txt.replace('eval', 'return') print(func_return) content = execjs.compile(func_return) eval_func = content.call('x') name = re.findall(r'var (.*?)=function.*', eval_func)[0] mode_func = eval_func.replace('while(window._phantom||window.__phantomas){};', ''). \ replace('document.cookie=', 'return').replace('if((function(){try{return !!window.addEventListener;}', ''). \ replace("catch(e){return false;}})()){document.addEventListener('DOMContentLoaded',%s,false)}" % name, ''). \ replace("else{document.attachEvent('onreadystatechange',%s)}" % name, '').replace( r"setTimeout('location.href=location.pathname+location.search.replace(/[\?|&]captcha-challenge/,\'\')',1500);", '') content = execjs.compile(mode_func) cookies = content.call(name) # print(cookies) clearance = cookies.split(';')[0] return clearancedef structureHeaders(cook, clearance): """ 構造新的headers :return: """ cookie = { 'cookie': cook + ';' + clearance } return dict(headers, **cookie)