這次講一個很重要的技巧:那就是利用代碼模擬登錄某些網(wǎng)站。
首先我們重點(diǎn)講下session以及cookiejar:官方文檔
"""A Requests session.
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
<Response [200]>
Or as a context manager::
>>> with requests.Session() as s:
>>> s.get('https://httpbin.org/get')
<Response [200]>
"""
大意是說session對象具有自動保存cookie等功能
cookiejar:
r"""HTTP cookie handling for web clients.
This module has (now fairly distant) origins in Gisle Aas' Perl module
HTTP::Cookies, from the libwww-perl library.
Docstrings, comments and debug strings in this code refer to the
attributes of the HTTP cookie system as cookie-attributes, to distinguish
them clearly from Python attributes.
Class diagram (note that BSDDBCookieJar and the MSIE* classes are not
distributed with the Python standard library, but are available from
http://wwwsearch.sf.net/):
CookieJar____
/ \ \
FileCookieJar \ \
/ | \ \ \
MozillaCookieJar | LWPCookieJar \ \
| | \
| ---MSIEBase | \
| / | | \
| / MSIEDBCookieJar BSDDBCookieJar
|/
MSIECookieJar
"""
講下cookiejar和session的關(guān)系侧啼,cookiejar是底層庫衣赶,可以形象的把cookiejar看作保存cookie的罐子间唉,cookie里面可以保存很多cookie偏塞。session的實(shí)現(xiàn)調(diào)用了底層cookejar,可以認(rèn)為session對象能把cookie對象自動保存到cookiejar中
使用session對象十分十分方便钉答,我們首先創(chuàng)造session對象础芍,用requests.session()就可以了,然后后面的所有網(wǎng)絡(luò)請求全部用session的get数尿,post函數(shù)等仑性,而不用requests對象的get,post函數(shù)右蹦,這樣session對象能自動保存訪問過的網(wǎng)頁設(shè)置的cookie
理論上我們使用session是不需要知道cookiejar是什么東西的诊杆,因?yàn)樵O(shè)計requests的人早就幫我們封裝好了一切。這里我還是講下cookiejar的用法
from http import cookiejar
from urllib import request
cookie_jar = cookiejar.CookieJar()
cookie_handler = request.HTTPCookieProcessor(cookie_jar)
cookie_opener = request.build_opener(cookie_handler)
# cookiejar保存cookie
cookie_opener.open('登陸頁面網(wǎng)址', timeout=10, data={'登陸的表單數(shù)據(jù)何陆,字典格式'})
# 用以及保存了cookie的opener對象去訪問別的網(wǎng)頁
response = cookie_opener.open('需要登陸后才能訪問的網(wǎng)頁')
我們再次感受到requests庫的簡便與強(qiáng)大晨汹。。我們這次爬取還是用session
我們在使用爬蟲的時候經(jīng)常會遇到某些必須要求我們登陸才能獲取到信息的情況贷盲,比如淘寶商品信息的爬取淘这。
這時候我們一般有兩種方式,第一種是手動設(shè)置cookies巩剖,具體見上一篇文章铝穷;
這篇文章里我們介紹下另外一種方法:代碼實(shí)現(xiàn)自動抓取cookies然后模擬登陸,這樣做有一個好處佳魔,只要你輸入正確的賬號密碼曙聂,就可以直接獲取到你想要獲取的信息。
廢話不多說鞠鲜,我們直接開始宁脊,然后這次我們選擇的目標(biāo)網(wǎng)站是我的母校的教務(wù)處網(wǎng)站,我準(zhǔn)備從中查詢到成績和課表信息:
我們首先要人工登陸镊尺,注意在登陸之前(就是輸入賬號密碼的那個網(wǎng)頁)打開開發(fā)者工具:我們把這個preserve log 勾選上朦佩,這個的意思是保存歷史信息,就是說跳轉(zhuǎn)到新的url后原來界面的network里面的元素還在而不會刷新掉庐氮。
找到all選項下的一個是POST請求的元素(一般在前面),把詳細(xì)信息拉到最下面會有一個form表單弄砍,這是post請求的參數(shù):
其中username和password就是你剛剛輸入的賬號和密碼仙畦,下面還有些參數(shù),有的需要有的不需要音婶。
這些是為了安全性創(chuàng)造的一些參數(shù)慨畸,尤其是lt參數(shù),其實(shí)就是一個隨機(jī)數(shù)衣式,每次刷新都不一樣寸士,但是lt參數(shù)你錯一個字母都無法成功登陸檐什,execution參數(shù)是你登陸了幾次的意思,如果你賬號密碼輸入錯誤他就會增加弱卡,比如從e1s1變成了e2s2可能乃正,然后你一直錯,它一直加婶博,最后可能在錯誤的次數(shù)達(dá)到一定程度后就給你上驗(yàn)證碼了瓮具,所以我們最好一次就成功登陸。
所以我第一個想啊就是先讓程序抓取這個登陸頁面的lt后忠荞,利用這個lt再去登陸蒋歌。
但是有個小問題:隨著我每次刷新帅掘,lt和execution都是在動態(tài)變化的委煤,這肯定不行(因?yàn)槟阕ト〉谝淮危喈?dāng)于第一次訪問登陸頁面修档,他給你第一次的lt碧绞,你再用第一次的lt去登陸的時候,吱窝,別人的lt在你登陸的過程中就變化了讥邻,生成了第二次的lt),那我們要怎么辦呢院峡? 以及它是根據(jù)什么判斷我們是第幾次訪問到登陸頁面的兴使??
答案就是 cookies
我們在每次進(jìn)入到登陸界面的網(wǎng)站照激,它會給我們設(shè)置一個cookies來判斷我們是第幾次訪問发魄,如果我們賬號密碼輸入錯誤,它的cookes也會變化俩垃,從而導(dǎo)致lt變化励幼。
也就是說,只要我們在獲取到lt后口柳,用當(dāng)時獲取到lt的cookies去發(fā)送登錄請求苹粟,就能正常登陸:
我們先看看cookie與lt的關(guān)系:
第二次請求:
從這里我們就可以看出cookie與lt的關(guān)系,可以這么簡單的理解:一個cookie對應(yīng)一個lt跃闹。
然后我們只要用前面請求lt的cookie去模擬登錄嵌削,它的lt就不會“刷新”毛好。
之后我們利用lt和其他參數(shù)拼接成的data字典傳給post請求的data參數(shù),生成網(wǎng)頁導(dǎo)入本地苛秕,打開后是這樣:就代表你成功登陸了睛榄,可以保存登陸后的cookies。
代表哪里出了問題想帅,要么是data參數(shù)不正確還是啥的场靴,這樣沒成功登陸是保存不了cookies的。 這樣港准,獲取了登陸后的cookies后旨剥,我們就可以用保存了cookies的session對象繼續(xù)去訪問里面的網(wǎng)站,比如成績網(wǎng)站:我們進(jìn)去后查看源網(wǎng)頁浅缸,隨便搜索一門課的成績:
沒有任何數(shù)據(jù)轨帜。這樣的網(wǎng)站我們已經(jīng)見過很多了,前面的搜狗百度圖片衩椒,都是這樣的蚌父,稱為瀑布流式網(wǎng)頁,Ajax動態(tài)網(wǎng)頁毛萌,我們利用開發(fā)者工具苟弛,抓取數(shù)據(jù):
在XHR項一個個找,看哪個是返回給我們的數(shù)據(jù)阁将,最后發(fā)現(xiàn)最下面的xscjx.do是成績數(shù)據(jù):
歐克膏秫,找到目標(biāo)url了,繼續(xù)爬茸鲋选:
人傻了缤削,我們不是登陸了嗎?怎么回事吹榴?
所以我們還要用session再登陸下這個成績網(wǎng)頁保存cookies:
然后再獲取數(shù)據(jù)就大功告成:
注意ajax的那個網(wǎng)頁返回的數(shù)據(jù)是json格式的帅刀。
這種最簡單搞了,直接轉(zhuǎn)成python字典婿斥,然后需要啥爬啥劝篷。
簡單處理下:
當(dāng)然你可以導(dǎo)入scv表格,做GUI界面民宿,反正數(shù)據(jù)都搞到了娇妓,做啥看興趣了。
比如你可以設(shè)置輸入賬號密碼:
課表的話類似吧活鹰,哈恰,以前沒搞過只估,現(xiàn)在試試:
這個可能代表是第幾學(xué)期的課表蛔钙,post下就歐克了。 結(jié)果完全沒問題昂:
當(dāng)然數(shù)據(jù)獲取到了荠医,你怎么去使用就看你的興趣了吁脱。
謝謝觀看@**@
源代碼:
# coding='utf-8'
import requests
from lxml import etree
class Spider:
def __init__(self, url='', path=''):
self.url = url if url else ''
self.path = path if path else ''
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
}
def get_response(self, url):
return self.session.get(url, headers=self.headers)
# 模擬登錄,保存cookie
def post_response(self, url, data):
return self.session.post(url, headers=self.headers, data=data)
def get_etree(self, xml):
return etree.HTML(xml)
def parse_data(self, target, fmt):
return target.xpath(fmt)
def set_data(self, name='', psw=''):
self.data = {
'username': name if name else '17030140051',
'password': psw if psw else 'ForeverLove520',
'lt': self.lt,
'execution': 'e1s1',
'_eventId': 'submit',
'rmShown': '1',
}
def set_lt(self, url):
response = self.get_response(url)
target = self.get_etree(response.content.decode('utf-8'))
result_list = self.parse_data(target, r'//input[@name="lt"]')
self.lt = result_list[0].get('value')
def start(self):
log_in_url = 'http://ids.xidian.edu.cn/authserver/login?service=http%3A%2F%2Fehall.xidian.edu.cn%2Flogin%3Fservice%3Dhttp%3A%2F%2Fehall.xidian.edu.cn%2Fnew%2Findex.html'
self.session = requests.session()
# 給的參數(shù)是登陸網(wǎng)頁,作用是抓取動態(tài)lt,同時保存cookies
self.set_lt(log_in_url)
name = input('輸入學(xué)號:')
psw = input('輸入密碼:')
self.set_data(name, psw)
# 模擬登錄
response = self.post_response(log_in_url, self.data)
# 這步必須要,成績網(wǎng)站也給我們設(shè)置cookies了
# 我們首先要獲取成績查詢所在的網(wǎng)址
# 這步真的搞哭我了....................一把辛酸淚
'''
# 這個可以用來搞到所有的可用的app
all_useable_url = 'http://ehall.xidian.edu.cn/jsonp/getUserAllUsableApp?searchKey=&_=1585880169428'
response = self.get_response(all_useable_url)
all_apps = response.json()['data']
for each in all_apps:
# 查成績:
if each['appName'] == '成績查詢':
score_appid = each['appId']
break
'''
score_appid = '4768574631264620'
# 只需要訪問這個臨時的網(wǎng)站我們就可以獲得cookies,然后去申請成績數(shù)據(jù)
temp_url = 'http://ehall.xidian.edu.cn//appShow?appId={}'.format(score_appid)
response = self.get_response(temp_url)
# 查成績的json url,開發(fā)者工具抓取
self.url = 'http://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx/xscjcx.do'
response = self.get_response(self.url)
score_list = response.json()['datas']['xscjcx']['rows']
print('\n\n成績:\n')
for each in score_list:
print(each['KCM'], ":", each['ZCJ'])
print('\n\n\n____________________________\n\n\n課表:\n')
course_end_url = 'http://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/xsllsykb.do'
response = self.post_response(course_end_url, {'XNXQDM': '2019-2020-2'})
course_list = response.json()['datas']['xsllsykb']['rows']
for each in course_list:
print(each['KCM'], ':', each['YPSJDD'])
Spider().start()
'''
from http import cookiejar
from urllib import request
cookie_jar = cookiejar.CookieJar()
cookie_handler = request.HTTPCookieProcessor(cookie_jar)
cookie_opener = request.build_opener(cookie_handler)
# cookiejar保存cookie
cookie_opener.open('https://image.baidu.com', timeout=10, data={'鍵':'值'})
# 用以及保存了cookie的opener對象去訪問別的網(wǎng)頁
response = cookie_opener.open('需要登陸后才能訪問的網(wǎng)頁')
'''
'''
from http import cookiejar
from urllib import request
cookie_jar = cookiejar.CookieJar()
cookie_handler = request.HTTPCookieProcessor(cookie_jar)
cookie_opener = request.build_opener(cookie_handler)
# cookiejar保存cookie
cookie_opener.open('https://image.baidu.com', timeout=10, data={'鍵':'值'})
# 用以及保存了cookie的opener對象去訪問別的網(wǎng)頁
response = cookie_opener.open('需要登陸后才能訪問的網(wǎng)頁')
'''