python爬蟲 處理521狀態碼

  在抓取數據的時候每每能夠經過狀態碼來判斷返回結果,今天在抓取數據的時候碰到了之前沒有碰到過得狀態碼521,輸出它的爬取內容(text),發現是一些js代碼。一塊兒探討一下如何處理521狀態碼。python

  用charles抓包的時候,發現瀏覽器對於同一網頁連續訪問了兩次,第一次的訪問狀態碼爲521,第二次爲200(正常訪問)。看來網頁加了反爬蟲機制,須要兩次訪問纔可返回正常網頁。瀏覽器

經過對比兩次請求,咱們發現第二次訪問帶了新的cookie值。再考慮上面程序對爬取結果的輸出爲js代碼,能夠考慮其操做過程爲:第一次訪問時服務器返回一段可動態生成cookie值的js代碼;瀏覽器運行js代碼生成cookie值,並帶cookie從新進行訪問;服務器被正常訪問,返回頁面信息,瀏覽器渲染加載。
 
弄清楚瀏覽器的執行過程後,咱們就能夠模擬其行爲經過python做網頁爬取。操做步驟以下:
  1. 用request.get(url)獲取js代碼服務器

  2. 執行函數eval()語句修改成return語句返回cookie值cookie

  3. 調用execjs執行js代碼得到cookie值函數

  4. 將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)