Python爬虫之urllib模拟登陆及cookie的那点事

在web  sprider crawl过程当中,许多网站都须要登陆后才能访问,通常若是咱们不用爬虫框架的前提下,常规用的就两个库 ,urllib库和requests库,本文将用最基础的urllib库,以模拟登陆人人网为例,理清爬虫过程当中登陆访问和cookie的思绪。


 

1.终极方案,也是最简单粗暴最有效的方式。直接手动登陆,提取cookie,下次访问直接在请求头携带cookie

       咱们知道,网站辨别用户身份和保持会话的经常使用方式就是cookie和session,用户登陆成功,服务器返回一些特定字符串保存在本地浏览器中(cookie),浏览器下次访问会直接携带cookie,这样服务器就能够根据返回的cookie验证访问者身份。一般若是用浏览器正常访问,这部分事情浏览器会帮咱们去作。可是在程序模拟登  录时候,携带cookie就须要手动携带了。话很少说,直接进入主题。html

    

 

 

    打开人人网登陆界面,填入本身正确的用户名和密码,成功登录进去。web

 

 

 

 

其中红色框的就是服务器给你的cookie,你的cookie就是以这样的形式在request请求头中的。直接将其复制粘贴下来,放入代码中。上程序:ajax

 

""" 首先手动登陆人人网,而后获取cookie """

from urllib.request import urlopen, Request headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', # 'Accept-Encoding': 'gzip, deflate', 这部分一般注释掉,由于这部分是高诉服务器,本地支持的压缩类型,由于浏览器会自动帮咱们解压,可是在程序中,没办法解压,因此请求头就不携带了
    'Accept-Language': 'zh-CN,zh;q=0.9', 'Connection': 'keep-alive', 'Cookie': 'anonymid=kcpawuyd33irh2a;depovince=GW;r01_=1; JSESSIONID=abcGzDX6FRQNVfwdUETBnx;ick_login=6a732399-3adf-471b-af92-9bd68299d515; \
    taihe_bi_sdk_uid=e4c3ee72270319312dde3088eb04c0be; taihe_bi_sdk_sefssion=6722a32d96ebbf8fd565fc7cc7f8f789;ick=1048bb79-0d32-46ab-8a11-af0c7e4cfa51;first_login_flag=1; \
    ln_uact=17795796865;ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; ga=GA1.2.2124318841.1594975538;gid=GA1.2.506855365.1594975538; \
    wp_fold=0;jebecookies=3833d4fe-20b3-4ecf-9efc-df9aca93641e|||||;de=5C6d0B07AA3EB53E377A21F126C928EF0; p=d3ae1effe255d4e057ef37f5682ac4850;\
    t=ba23da27a155cc2b84a43307e83b37a70;societyguester=ba23da27a155cc2b84a4f3307e83b37a70;id=974774570;xnsid=a3c6bde2;ver=7.0;loginfrom=null
', 'Host': 'www.renren.com', 'Referer': 'http://www.renren.com/974774570/profile''Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36' } url = 'http://www.renren.com/974774570/profile' #我的主页 request = Request(url=url, headers=headers) response = urlopen(request) print(response.read().decode())

   注释:程序的headers 是一个字典,是经过登陆后抓包来的以下:浏览器

 

 

 

 

 

 

    其实一般咱们只须要携带图中的两个参数,cookie和User-Agent,,某些get请求中,只需假装User_agent便可。可是我为何带这么多呢,那是由于,在有的网站你抓取的过程当中,你其余参数都配置完美,可是老是抓取错误,那么问题八九不离十出如今headers中,始终记住咱们是用程序模拟浏览器访问服务器,说明程序假装的还不够完美。缓存

 那么这时候就要考虑headers中是否缺失了某些头部信息。为了防止出错,干脆全盘端过来,反正你浏览器访问的时候就是带的这些请求头参数。可是要注意,请求头Accept-Encoding (程序中已经交代清楚)和 Content-Length(这是浏览器计算出的长度,程序模拟没办法计算,因此注释掉)一般注释掉。服务器

 

 HTTP请求中的经常使用消息头cookie

  accept:浏览器经过这个头告诉服务器,它所支持的数据类型
  Accept-Charset: 浏览器经过这个头告诉服务器,它支持哪一种字符集
  Accept-Encoding:浏览器经过这个头告诉服务器,支持的压缩格式
  Accept-Language:浏览器经过这个头告诉服务器,它的语言环境
  Host:浏览器经过这个头告诉服务器,想访问哪台主机
  If-Modified-Since: 浏览器经过这个头告诉服务器,缓存数据的时间
  Referer:浏览器经过这个头告诉服务器,客户机是哪一个页面来的  防盗链
  Connection:浏览器经过这个头告诉服务器,请求完后是断开连接仍是何持连接session

  Content-Length:浏览器经过这个头告诉服务器发出去的字节长度app

2. 模拟登陆,而后访问主页(在程序中咱们不须要关心cookie是如何如何的,opener对象会自动帮咱们处理,与之对应的是方式3,见下文)


 

 

 

      

 

 

 经过抓包如上图,分析登陆post请求的地址和携带的参数框架

      

 

 

 直接上代码:

"""
真正的模拟登陆是:发送post请求以后,保存cookie,以后访问携带cookie
"""
# http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020652227884 经过这13位数,咱们能够以男人的直觉,嗅出这是精确到毫秒的时间戳,那m咱们给他生成就是
url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp={}'  # 登陆地址
import time
from urllib.request import Request, urlopen, HTTPCookieProcessor, build_opener, ProxyHandler
from urllib.parse import urlencode
from http.cookiejar import CookieJar, MozillaCookieJar

# 1. 建立cookiejar对象,这一种方式不用手动保存cookie,后期直接调用同一个opener便可,由于cookie已经在opener对象中
cookiejar = CookieJar()

# 2.经过cookiejar建立一个handler
handler = HTTPCookieProcessor(cookiejar)
# handler1 = ProxyHandler({'http': '182.101.207.11:8080'})     # 选择是否须要代理(本身设定代理)
# 3.根据handler建立一个opener
opener = build_opener(handler)  # build_opener以传递多个handler对象,若是须要代理,则将handler1也传入
unique_time = int(time.time() * 1000)  # 生成时间戳

headers = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36'
}

data = {
    'email': '17795796865',
    'icode': '',
    'origURL': 'http://www.renren.com/home',
    'domain': 'renren.com',
    'key_id': '1',
    'captcha_type': 'web_login',
    # 此处密码是通过目标网站加密,不能直接放置原生密码,加密密码能够用浏览器抓包获取
    'password': '4af866303efsdf40a11d9f01e9677f3374bb957f905790b62a7eaa1accaf0a634764a1',
    'rkey': '1ad002b47d8446d446f8d76f5bb5ff66',
    'f': 'http%3A%2F%2Fwww.renren.com%2F974774570%2Fnewsfeed%2Fphoto'
}
# 4 建立request对象
request = Request(url=url.format(unique_time), headers=headers)
# 5.post方式提交登陆
respose = opener.open(request, data=urlencode(data).encode())
print(respose.read().decode())
print('*' * 50)

# get方式访问我的主页
get_url = 'http://www.renren.com/974774570/profile'
request = Request(url=get_url, headers=headers)
respose = opener.open(request)
print(respose.read().decode())

      注释:data中的数,咱们一个都不能少,由于post请求中,抓包能够看到,浏览器就带的这么多参数。至于参数是什么意思,咱们惟一能一眼看懂的就是email(用户名)和password(密码)。密码是加密后的,必定不能写原生密码,加密后这一窜密码能够用浏览器登陆抓包获取。至于其余的参数,这就是爬虫的难点,好比像大型的互联网公司如淘宝,这里的data参数动辄几十个,要破解至关有难度,咱们暂且不须要关注这些,可是一般的网站咱们稍做分析大概就能猜出来这里某个参数的意思,实在猜不出来,就原生不动的放着试着登陆。大不了登陆不进去我么能够采起上面的终极方案啊。始终记住,爬虫工程师,获取到网页提取数据才是你的重点。不要把精力耗费到破解form_data中的参数上。

3.手动将cookie保存到本地文件中,后续请求中直接读取该cookie文件便可


可能有的人就有疑问了,方式2既然能模拟登陆成功,那为何还要手动保存在本地呢,岂不是画蛇添足。凡事存在即合理。在爬虫过程当中,咱们能够手动提取cookie,或者模拟登陆,可是在分布式爬虫或者多台机器同时爬取时候,若是让每台机器都要copy cookie,或者让每台机器都登陆一遍,这不是明智的选择,那么只有事先将cookie保存在文件中,后续每台机器的程序从文件中读取便可。

程序和方式2的程序很类似:

import time
from fake_useragent import UserAgent
from urllib.request import Request, urlopen, HTTPCookieProcessor, build_opener, ProxyHandler
from urllib.parse import urlencode
from http.cookiejar import CookieJar, MozillaCookieJar
from time import sleep

url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp={}'


# 模拟登陆
def save_cookie():
    # 1. 建立cookiejar对象
    # cookiejar = CookieJar()  # 这一种不用保存文件中,后期直接用同一个opener对象调用就行
    cookiejar = MozillaCookieJar()  # 这种方式是将cookie保存文件中
    # 2.经过cookiejar建立一个handler
    handler = HTTPCookieProcessor(cookiejar)
    # handler1 = ProxyHandler({'http': '182.101.207.11:8080'})     # 选择是否须要代理
    # 3.根据handler建立一个opener
    opener = build_opener(handler)  # 能够传递多个handler对象,若是须要代理,则将handler1也传入
    unique_time = int(time.time() * 1000)  # 生成时间戳

    headers = {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36'
    }

    data = {
        'email': '17795796865',
        'icode': '',
        'origURL': 'http://www.renren.com/home',
        'domain': 'renren.com',
        'key_id': '1',
        'captcha_type': 'web_login',
        # 此处密码是通过目标网站加密,不能直接放置原生密码,加密密码能够用浏览器抓包获取
        'password': '4af866303e40a11901e9677f3374bb957f905790b62a7eaa1accaf0a634764a1',
        'rkey': '1ad002b47d8446d446f8d76f5bb5ff66',
        'f': 'http%3A%2F%2Fwww.renren.com%2F974774570%2Fnewsfeed%2Fphoto'
    }

    request = Request(url=url.format(unique_time), headers=headers)
    respose = opener.open(request, data=urlencode(data).encode())
    # 建立保存能够序列化cookie的文件对象
    cookiejar.save('cookiejar.txt', ignore_discard=True, ignore_expires=True)
    print(respose.read().decode())
    print('*' * 50)


# 访问我的主页
def use_cookie():
    get_url = 'http://www.renren.com/974774570/profile'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36'
    }
    # 1. 建立cookiejar
    cookiejar = MozillaCookieJar()
    # 2.从本地加载cookie文件
    cookiejar.load('cookiejar.txt')
    # 3.建立handler对象
    handler = HTTPCookieProcessor(cookiejar)
    # 4.建立opener对象
    opener = build_opener(handler)
    # 5.建立request对象
    request = Request(url=get_url, headers=headers)
    # 6.发送请求
    respose = opener.open(request)
    print(respose.read().decode())


if __name__ == '__main__':
    save_cookie()
    sleep(2)
    use_cookie()

运行程序咱们能够看到本地有个cookiejar.txt文件

 

 

总结


 

   无论以哪一种方式,咱们的终极目的是为了爬取数据,而不是花里胡哨的模拟登录,若是模拟登录过程当中几回尝试失败,那么不妨能够直接放弃,直接以第一种方式便可。毕竟人生苦短!因为精力有限,此处就没有涉及验证码,一般大多数网站登录几回失败后就有验证码验证。后续有机会再讲。

相关文章
相关标签/搜索