在抓取数据的时候每每能够经过状态码来判断返回结果,今天在抓取数据的时候碰到了之前没有碰到过得状态码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)