1
import requests 2 import os 3 from PIL import Image 4 import pytesseract 5 import re 6 7 rootUrl = xxx 8 # 构建登录页面url 9 loginUrl = rootUrl + '/sipopublicsearch/portal/uilogin-forwardLogin.shtml' 10 # 构建登陆页面headers 11 rootHeaders = { 12 'Cache-Control': 'max-age=0', 13 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 14 'Accept-Encoding': 'gzip, deflate', 15 'Accept-Language': 'zh-CN,zh;q=0.9', 16 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36', 17 'Upgrade-Insecure-Requests': '1', 18 'Connection': 'keep-alive', 19 'Host': 'www.pss-system.gov.cn' 20 } 21 # 保持会话,建立session 22 s = requests.session() 23 # get 之后打印cookies,发现其中缺了一项cookie,这里手动添加 24 requests.utils.add_dict_to_cookiejar(s.cookies,{'avoid_declare':'declare_pass'}) # 使用utils.add_dict_to_cookiesjar()是保存到session里面 25 r =s.get(url=rootUrl,headers=rootHeaders,verify=False) # 在某段时间内可以一直存在 26 print(s.cookies.get_dict()) 27 # 请求 验证码链接 ,下载图片 28 # 构建验证码链接 29 verifyUrl = rootUrl + '/sipopublicsearch/portal/login-showPic.shtml' 30 # 构建请求验证码的headers 31 verifyHeaders = { 32 'Cache-Control': 'max-age=0', 33 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 34 'Accept-Encoding': 'gzip, deflate', 35 'Accept-Language': 'zh-CN,zh;q=0.9', 36 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36', 37 'Upgrade-Insecure-Requests': '1', 38 'Connection': 'keep-alive', 39 'Host': rootUrl, 40 'Referer': rootUrl + '/sipopublicsearch/portal/uilogin-forwardLogin.shtml', 41 } 42 verifyCode = s.get(url=verifyUrl,headers=verifyHeaders,verify=False) 43 os.chdir(r'更改保存验证码图片路径') 44 with open('verifycode.png','wb') as f: 45 f.write(verifyCode.content) 46 f.close() 47 png = Image.open(r'verifycode.png') 48 # pip 出问题了 ,装不了 tesseract ,只能手动识别了 49 #verifycode = pytesseract.image_to_string(png) 50 #print('验证码为【{}】,'.format(verifycode),end='') 51 png.show() 52 mycode = input('请输入答案:') 53 54 # 提交表单的 第一个请求是 post ,然后从headers中取出 下一个跳转的url 55 # 先构建post的url, 其中参数 V 其实可以做成一个自动变化的参数,这里就不做了 56 jumpUrl = rootUrl + '/sipopublicsearch/wee/platform/wee_security_check?v=20180802' 57 jumpHeaders = { 58 'Cache-Control': 'max-age=0', 59 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 60 'Accept-Encoding': 'gzip, deflate', 61 'Accept-Language': 'zh-CN,zh;q=0.9', 62 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36', 63 'Upgrade-Insecure-Requests': '1', 64 'Connection': 'keep-alive', 65 'Host': rootUrl, 66 'Referer': rootUrl + '/sipopublicsearch/portal/uilogin-forwardLogin.shtml', 67 'Origin': rootUrl, 68 'Content-Type': 'application/x-www-form-urlencoded', 69 'Content-Length': '108', 70 } 71 postData = { 72 'j_loginsuccess_url':'', # 这个值为空,用两个引号表示空值,不能换 None 哦!! 73 'j_validation_code':mycode, 74 'j_username':用户名, # 用户名和密码是加密过的,不过还好不是动态变化的加密,不然就麻烦了 75 'j_password':密码, 76 } 77 # post 请求 78 postResponse = s.post(url=jumpUrl,data=postData,headers=jumpHeaders,verify=False) 79 # 测试是否已经进爬取页面 80 from lxml import etree 81 html = etree.HTML(postResponse.text) 82 testEle = html.xpath('//div[@class="wrap-left"]/p/text()')[0] 83 print(testEle) # 这里已经显示 【 xxx用户名,欢迎访问!】 表示已经进入爬取页面了 84 85 # 可以像下面这样写到本地,方便自己查看,Txt还要注意 需要 编码成 utf-8 86 with open('content.txt','w',encoding='utf-8') as c: 87 c.write(postResponse.text) 88 c.close() 89 print(postResponse.status_code) 90 91 # 这下面的都不要了 ,因为上面就已经进去了,下面这段代码对应的响应位于【发送post请求】与【获取真正可以爬取页面】之间的跳转页面
92 ''' 93 # 获取响应中跳转的url 94 pattern = re.compile(r'<a href="(.*?)">') 95 reUrl = pattern.search(postResponse.text) 96 getUrl = reUrl.group(1) 97 print(reUrl.group(1)) 98 99 # 提交表单的第二次请求是 get , 100 # url:getUrl ; headers: jumpHeaders 101 print(s.cookies.get_dict()) 102 getResponse = s.get(url=getUrl,headers=jumpHeaders,verify=False) # 这里请求的cookies和 headers 应该是只能按它需要的发送,不能发多 103 print(getResponse.url) 104 print(getResponse.headers) 105 print(s.cookies.get_dict()) 106 # re2Url = pattern.search(getResponse.text) 107 # lastUrl = re2Url.group(1) 108 # print(re2Url.group(1)) # 得到 /sipopublicsearch/portal/uiIndex.shtml 109 # get2Url = nethost + lastUrl 110 111 # 进入真正的登陆后的页面 112 # 拿最后获取的 get2Url 进入登陆后页面 113 # lastResponse = s.get(url=get2Url,headers=jumpHeaders,verify=False) 114 # print(lastResponse.status_code) 115 # print(lastResponse.url) 116 '''

上面这段代码是登陆某检索网站的全部思路,其中对于登陆该网站而言真正有用的是【1~90行】,那为什么还有这么多呢?那是因为之前的经验蒙蔽了我得双眼,比如下面这两者情况:

第一种爬虫(二)requests 登陆某检索网站

 

第二种爬虫(二)requests 登陆某检索网站

【这里开始分析】: 以前碰到的是上图中第一种;那儿有两个框,分别标了1和2;2代表的是真正请求的爬取网站,1代表真正请求前跳转的网站,一般这种跳转网站字节少,上面箭头已给出对比;两个框里面的状态码 都是200,表示这都是有响应的,通常情况下,这种跳转网页的响应中都包含了真正请求爬取网站所需的参数或者cookie,因此要登陆这种有跳转的爬取网站都必须先去跳转网站获取数据;这里有难度的登陆网站【个人经验】会做以下几点:(1)将跳转网站链接参数用js加密,让大部分爬虫挂在这儿,(2)不加密跳转网站链接参数,转为js加密数据【哪些数据?那些在处理登陆问题时要用到的数据】(3)上述两个不全加密 (4 )【有哪些加密方法啊?这个我晓得几个,不过现在还无法搞定,等能搞定再写一篇解密】

  上图中第二种:框框共有4个,其中2和3明显属于页面跳转链接,于是经验使然,直接打开fiddler开始分析链接参数啊、下一步需要的数据啊,哎,发现两个都没有加密过,只是位置变来变去,ok,没什么大问题,搞定后开始将数据代入真正请求的爬取网址,代码开始运行....

然后就发现...好像将表单提交之后,就已经进入爬取页面了。 嗯??!! WTF ? 那我后面还搞了这么多,不是瞎搞啊 ? 什么情况呢?

然后就发现上图框框中标记的1、2、3、4啊,前面的状态码,不太对! 中间那两个302是什么意思? 呃 ? 忘了,然后baidu ,哦?302表示临时的url重定向url!! 原来是这样,难怪不用我自己发送请求,原来是多此一举【总结这个网站,呃,除了数据绕了点,好像其他没上什么高难度的操作,嗯,很友好我喜欢!!!】

【结语】此次目的就是登陆,因此写了登陆时测试的代码【呸,写的都是什么,这么乱还能叫代码?】,如果后续要爬取数据的话,思路是这样的:

1、加入ip代理【先测试一个ip能爬多少个,然后退出登陆,换headers,ip重新登陆再爬取,这样循环...】

2、引入线程【一个爬数据,一个存数据到本地(啥形式?随便。注意存的时候要查下重),主要是为了防止:一旦错误发生,数据全部丢失,又得重来】

3、如果有大量url,那就建个url管理器,并将url实时导入导出到本地【这样一旦发生错误,还可以从断开的url继续爬,虽然要牺牲些时间】

【最后】

【有一个问题求助:在某个链接的参数上遇到了【MmEwMD】这个js加密,求个例子解法】