相信最開始接觸Python爬蟲學習的同學最初大多使用的是urllib,urllib2。在那之后接觸到了第三方庫requests,requests完全能滿足各種http功能,真的是好用爆了 :D
他們是這樣說的:
“Requests 唯一的一個非轉基因的 Python HTTP 庫,人類可以安全享用。Requests 允許你發送純天然,植物飼養的 HTTP/1.1 請求,無需手工勞動。你不需要手動為 URL 添加查詢字串,也不需要對 POST 數據進行表單編碼。Keep-alive 和 HTTP 連接池的功能是 100% 自動化的,一切動力都來自於根植在 Requests 內部的 urllib3。”
-----來自官方文檔(http://cn.python-requests.org/zh_CN/latest/)
敲入命令“Pip Install Requests”安裝即可享用(前提是已經安裝了pip)
還等什么呢?趕緊import requests加入豪華午餐吧
先看看幾個常用的方法和屬性:
1.requests.Session()這樣就可以在會話中保留狀態,保持cookie等
2.requests.get()獲取某個網頁,get時你可以使用params參數發送一些數據過去
d = {key1 : value1, key2 : value2 }
requests.get(‘URL’, params=d)
get時也可以使用headers參數定制請求頭。
h = {key1 : value1, key2 : value2 }
requests.get(‘URL’, headers=d)
3.requests.post()發送post請求,類似的,post時也可以發送數據(使用data參數)和定制請求頭(使用headers參數)。
一些常用的屬性:
eg=requests.get() eg.text #可以獲取響應的內容如抓回來的網頁 eg. encoding='utf-8' #有時回來的是亂碼,改變編碼以使其正常顯示根據實際情況改變編碼utf-8、gb2312等 eg. content #可以獲取二進制內容,如抓取登陸時的驗證碼等非字符資源 eg.cookies #可以查看當前保存的cookie情況 eg. status_code #可以查看HTTP狀態碼(如200 OK、404 Not Found等) eg.url #可以查看當前請求的網址
其他詳細內容參見官方文檔(http://cn.python-requests.org/zh_CN/latest/)
好了,其實只要懂那么一點點就可以進行爬蟲之旅了。
一個有趣的現象:童鞋們在學習爬蟲時都會去爬一個叫做“教務處”的網站,哈哈。那這里的小爬蟲也是以登陸本校(成都信息工程大學)的教務處作為實例
首先使用瀏覽器打開教務處,按F12打開“開發人員工具”,進行一次正常的登陸,對登陸的數據進行分析。
1.教務處的登陸頁面為http://210.41.224.117/Login/xLogin/Login.asp
2.在開發者工具中點擊網絡,經查看登陸的發送post數據的地址也是http://210.41.224.117/Login/xLogin/Login.asp
3.同時看到post的數據包括如下
參數列表
|
||
表單名 |
例 |
說明 |
WinW |
1366 |
屏幕分辨率-寬 |
WinH |
728 |
屏幕分辨率-高 |
txtId |
2013215042 |
學號 |
txtMM |
123456 |
密碼 |
verifycode |
123a |
驗證碼 |
codeKey |
597564 |
動態登陸碼,html文件中可見 |
Login |
Check |
登陸類型(固定) |
IbtnEnter.x |
10 |
登陸按鈕點擊位置 |
IbtnEnter.y |
10 |
登陸按鈕點擊位置 |
“開發者工具”中的登陸post表單數據:
4.其中codeKey在登陸頁載入時可以在頁面中獲得(使用正則表達式獲取)。
那么思路來了:
1.get()載入登陸頁
2.在載入頁中獲取codeKey和驗證碼
3.使用post()將登陸學號、密碼、驗證碼等參數發送過去
4.登陸成功。
然而事實並不是如此順利,經以上思路登陸之后會返回“LoginOK!”登陸成功的消息,本來是要經兩個302跳轉到教務處的學生主頁的,但並不能順利跳轉而且哪怕手動加載學生頁不行。
經再次分析發現從教務處首頁點擊登陸鏈接並不是直接鏈接到登陸頁http://210.41.224.117/Login/xLogin/Login.asp,而是先訪問http://jxgl.cuit.edu.cn/JXGL/xs/MainMenu.asp試圖打開學生頁失敗,再經跳轉到一個http://210.41.224.117/Login/qqLogin.asp?Oid=jxgl.cuit.edu.cn&OSid=*********再經這里跳轉才到登陸頁,其中的OSid為服務器下發分配的。實踐表明我需要模仿這個過程才能順利登陸成功。
好了,那么思路再次來了:
- get(‘http://jxgl.cuit.edu.cn/JXGL/xs/MainMenu.asp’)這里要get兩次才能跳轉到登陸頁
- 在載入的登陸頁中獲取codeKey和驗證碼
- 使用post()將登陸學號、密碼、驗證碼等參數發送過去
- 登陸成功,加載學生主頁
要點:
- 兩次get()之后得到一個跳轉頁面由瀏覽器執行javascript自動跳轉,但在爬蟲里需要在這個頁面中找出跳轉的地址手動跳轉過去。使用正則表達式在javascript代碼中獲取需要跳轉的網址,再get該網址即可。
- 獲取驗證碼,驗證碼是隨機生成的,得到驗證碼刷新地址http://210.41.224.117/Login/xLogin/yzmDvCode.asp?k=597564&t=1471855009329其中參數k為codeKey,t為時間戳加上三位隨機數。那就使用前邊提到eg. content可以獲取二進制內容將圖片保存下來再打開人工識別后輸入驗證碼。
思考完畢,接下來就是實現了,最后的登陸代碼如下:
#coding=utf-8 import requests import re import time import random from PIL import Image import cStringIO def login(username,password): headers = { #請求頭請求刷新驗證碼和發送post時需要使用 'Host': '210.41.224.117', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0', 'Accept': '*/*', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Referer': 'http://210.41.224.117/Login/xLogin/Login.asp', 'Connection': 'keep-alive' } session = requests.Session() step1 = session.get('http://jxgl.cuit.edu.cn/JXGL/xs/MainMenu.asp') #連get兩次學生主頁以跳轉至登陸頁 step1 = session.get("http://jxgl.cuit.edu.cn/Jxgl/Xs/MainMenu.asp") get_osid_url = re.compile(r'content="0;URL=(.*?)">') #獲取含OSid的跳轉網址 osid_url = get_osid_url.findall(step1.text) step2 = session.get(osid_url[0]) #跳轉,上文要點1 get_codeKey = re.compile(r'var codeKey = \'(.*?)\';') #在登陸頁html中獲取codeKey(參數k) codeKey = get_codeKey.findall(step2.text) timeKey = str(time.time())[:10] + str(random.randint(100, 999)) #生成參數t的值(時間戳+三位隨機數) payload = {'k': codeKey[0], 't': timeKey} yzm_url='http://210.41.224.117/Login/xLogin/yzmDvCode.asp' yzmdata = session.get(yzm_url, params=payload, headers=headers) #刷新驗證碼,上文要點2 tempIm = cStringIO.StringIO(yzmdata.content) im = Image.open(tempIm) im.show() yzm = raw_input('please enter yzm: ') #人工識別驗證碼后輸入 post_data = { 'WinW': '1366', 'WinH': '728', 'txtId': username, 'txtMM': password, 'verifycode': yzm, 'codeKey': codeKey[0], 'Login': 'Check', 'IbtnEnter.x': 10, 'IbtnEnter.y': 10 } post_url='http://210.41.224.117/Login/xLogin/Login.asp' step3 = session.post(post_url, data=post_data, headers=headers) #post登陸數據 return session cuitJWC=login('username','password') con=cuitJWC.get('http://jxgl.cuit.edu.cn/JXGL/xs/MainMenu.asp') con.encoding='gb2312' print con.text