[繼豆瓣抓站后再對Coursera下手](http://www.jianshu.com/p/f76bd2164856)
> 系統:Mac OS X 10.10.1
> 編輯器: Sublime Text2
> Python版本: 2.7.8
> 模塊依賴: import sys, string, re, random, urllib, urllib2, cookielib, getpass(`均為系統內的模塊`)
* * *
# 0\. 抓站小結
## 0.1\. cookie處理
需要進行登陸的時候, 要進行cookie的處理,使用以下方法
~~~
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
urllib2.install_opener(opener)
req = urllib2.Request(url)
content = urllib2.urlopen(req)
~~~
## 0.2\. 表單處理
某些網站需要進行賬戶和密碼登陸, 需要使用POST方法向服務器發送賬戶和密碼表單數據, 這里就需要模擬登陸.
> 如何獲取表單數據的格式呢?
通過谷歌瀏覽器開發者工具中Network鎖定請求頭部和post發出的表單數據,偽裝表單數據
> 當由于Method太多, 找不到POST提交登錄請求Method方法的時候, 可以嘗試使用錯誤密碼, 這樣就可以容易的找POST方法對應的頭部.

找到POST方法

表單處理
~~~
form_data = urllib.urlencode({ #注意urlencode方法
"email": self.user_name,
"password": self.password,
"webrequest": "true"
})
~~~
## 0.3\. 防盜鏈和偽裝成瀏覽器訪問
防盜鏈就是需要在請求的頭部加入`Referer`字段, Referer 指的是HTTP頭部的一個字段, 用來表示從哪兒鏈接到目前的網頁,采用的格式是URL。換句話說,借著 HTTP Referer 頭部網頁可以檢查訪客從哪里而來,這也常被用來對付偽造的跨網站請求。
偽裝成瀏覽器就是將`User-Agent設置為瀏覽器的字段`

偽裝頭部
~~~
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/38.0.2125.111 Safari/537.36")
request_header = {
"Referer": "https://accounts.coursera.org/signin", #對付防盜鏈設置, 為跳轉來源的url
"User-Agent": user_agent, #偽裝成瀏覽器訪問
}
~~~
# 1\. 偽裝頭部
使用`谷歌瀏覽器自帶的開發者工具`, 選擇`Network`(`Element用來查看網站源碼等功能`), 獲取詳細的GET和POST方法, 從中獲取`登錄請求`的的頭部信息,
從POST中獲得Headers信息如下(`省略部分不重要信息`)
~~~
Request URL:https://accounts.coursera.org/api/v1/login //真正的登陸驗證頁面
Request Method:POST
Status Code:401 Unauthorized
//Request Headers
Connection:keep-alive
Content-Length:55
Content-Type:application/x-www-form-urlencoded
Cookie:(省略cookie信息, 下面詳細介紹)
...
Referer:https://accounts.coursera.org/signin //防盜鏈設置
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 //瀏覽器瀏覽標識
//下面四行為服務器所做的限制字段
X-CSRF2-Cookie:csrf2_token_el67QDLg
X-CSRF2-Token:1oxZDVMuZGX0qCggdReQyj2R
X-CSRFToken:WnVtiMDpvw0JXJqHjPrFk0EU
X-Requested-With:XMLHttpRequest
//Form Data
email:1095...@qq.com //Coursera賬戶信息
password:FAFA //賬戶密碼
webrequest:true //固定字段
~~~
這樣就能寫出模擬頭部的函數
~~~
def structure_headers(self) :
#模擬表單數據,這個參數不是字典
form_data = urllib.urlencode({
"email": self.user_name,
"password": self.password,
"webrequest": "true"
})
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/38.0.2125.111 Safari/537.36")
request_header = {
"Referer": "https://accounts.coursera.org/signin", #對付防盜鏈設置, 為跳轉來源的url
"User-Agent": user_agent, #偽裝成瀏覽器訪問
}
return form_data, request_header
~~~
試了幾次竟然都是`400錯誤`, 也就是頭部請求的格式不正確, 通過多次Headers查看, 發現有下面四處不同的頭部
~~~
X-CSRF2-Cookie:csrf2_token_hTu4Zy8Y 最后八位不同
X-CSRF2-Token:O5OIRan9I99lTHmnYS27ocYb 完全隨機
X-CSRFToken:HClYbs9HZoGweU54iR5r5z2y 完全隨機
X-Requested-With:XMLHttpRequest 固定不變
~~~
> 通過放上搜索找到了解決方案, coursera的請求頭部中`X-CSRF2-Token和X-CSRFToken`是完全隨機的, `X-CSRF2-Cookie`后八位是隨機生成的, 都是由字母和數字隨機生成的.
于是修改代碼如下:
~~~
def structure_headers(self) :
#模擬表單數據,這個參數不是字典
form_data = urllib.urlencode({
"email": self.user_name,
"password": self.password,
"webrequest": "true"
})
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/38.0.2125.111 Safari/537.36")
XCSRF2Cookie = 'csrf2_token_%s' % ''.join(self.random_string(8))
XCSRF2Token = ''.join(self.random_string(24))
XCSRFToken = ''.join(self.random_string(24))
cookie = "csrftoken=%s; %s=%s" % (XCSRFToken, XCSRF2Cookie, XCSRF2Token)
request_header = {
"Referer": "https://accounts.coursera.org/signin", #對付防盜鏈設置, 為跳轉來源的url
"User-Agent": user_agent, #偽裝成瀏覽器訪問
"X-Requested-With": "XMLHttpRequest",
"X-CSRF2-Cookie": XCSRF2Cookie,
"X-CSRF2-Token": XCSRF2Token,
"X-CSRFToken": XCSRFToken,
"Cookie": cookie
}
return form_data, request_header
def random_string(self, length):
return ''.join(random.choice(string.letters + string.digits) for i in xrange(length))
~~~
# 2\. 模擬登陸
登陸coursra的下載頁面時[計算機組成視頻下載](https://class.coursera.org/pkuco-001/lecture), 會發現是要求登陸呢, 這時候就使用`cookielib`模塊進行cookie的處理
~~~
def simulation_login(self) :
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
urllib2.install_opener(opener)
form_data, request_header = self.structure_headers()
req = urllib2.Request(self.login_url, data = form_data, headers = request_header)
try :
result = urllib2.urlopen(req)
except urllib2.URLError,e :
if hasattr(e, "code"):
print "The server couldn't fulfill the request.Please check your url and read the Reason"
print "Error code: %s" % e.code
elif hasattr(e, "reason"):
print "We failed to reach a server. Please check your url and read the Reason"
print "Reason: %s" % e.reason
sys.exit(2)
if result.getcode() == 200 :
print "登陸成功..."
~~~
這個函數用于模擬登陸, 并顯示登陸成功或者失敗
# 3\. 抓取下載鏈接
抓取鏈接通過正則表達式, 主要匹配`PDF下載鏈接和MP4視頻下載鏈接`
使用`re.findall()`函數進行函數匹配
~~~
def get_links(self) :
try :
result = urllib2.urlopen(self.url)
except urllib2.URLError,e :
if hasattr(e, "code"):
print "The server couldn't fulfill the request."
print "Error code: %s" % e.code
elif hasattr(e, "reason"):
print "We failed to reach a server. Please check your url and read the Reason"
print "Reason: %s" % e.reason
sys.exit(2)
content = result.read().decode("utf-8")
print "讀取網頁成功..."
down_links = re.findall(r'<a.*?href="(.*?mp4.*?)"', content)
down_pdfs = re.findall(r'<a.*?href="(.*?pdf)"', content)
print "正則匹配結束..."
return down_links, down_pdfs
~~~
# 4\. 寫入完本
既然已經匹配了所有的鏈接, 這一步就是將鏈接寫入到文件中
~~~
def start_spider(self) :
self.simulation_login()
down_links, down_pdfs = self.get_links()
with open("coursera.html", "w+") as my_file :
print "下載鏈接的長度", len(down_links)
for link in down_links :
print link
try :
my_file.write(link + "\n")
except UnicodeEncodeError:
sys.exit(2)
with open("coursera.pdf", "w+") as my_file :
print "下載pdf的長度", len(down_pdfs)
for pdf in down_pdfs :
try :
my_file.write(pdf + "\n")
except UnicodeEncodeError :
sys.exit(2)
print "抓取Coursera課程下載鏈接和pdf鏈接成功"
~~~
# 5\. 登陸調用
使用`getpass模塊中的getpass()`輸入密碼, 使用這個函數輸入密碼的時候不會顯示任何字符, 貌似體驗不好, 下次修改一下, 然后命令行傳入下載課程的參數.
通過比較每門課下載頁面, 發現之后`/lecture`前的這個字段是不同的,這樣可以設置通過命令行傳入這這個參數
[https://class.coursera.org/pkuco-001/lecture](https://class.coursera.org/pkuco-001/lecture)
[https://class.coursera.org/electromagnetism-001/lecture](https://class.coursera.org/electromagnetism-001/lecture)
> 這里在運行命令行只需要傳入`pkuco-001或者electromagnetism-001`這種字段
~~~
def main() :
if len(sys.argv) != 2 :
print "Please Input what course you want to download.."
sys.exit(2)
url = "https://class.coursera.org/{course}/lecture"
user_name = raw_input("Input your Email > ")
password = getpass.getpass("Input your Password > ")
spider = Coursera(url.format(course = sys.argv[1]), user_name, password)
spider.start_spider()
~~~
# 6\. 下載腳本
下載可以使用`curl`, Mac下安裝方法
~~~
brew install curl
~~~
編寫下載使用的Python腳本, 編寫成功后, 修改腳本文件的文件權限
~~~
chmod 755 downloadshell.py #最后一個參數為Python腳本名稱
~~~
運行下載腳本
~~~
$python downloadshell.py coursera.pdf #最后一個參數為連接保存文件
~~~
下面是我自己編寫的簡單的下載腳本
~~~
#!/usr/bin/python2
# -*- coding:utf-8 -*-
#簡單的文件下載腳本
import os
import sys, re
def read_file(file_name) :
down_links = []
with open(file_name, "r") as my_file :
for url in my_file :
down_links.append(url.replace("\n", ""))
return down_links
def main() :
if len(sys.argv) != 2 :
print "Please input file name..."
sys.exit(2)
down_links = read_file(sys.argv[1])
pdf_index = 1
mp4_index = 1
for index, link in enumerate(down_links) :
if link.find("mp4") != -1 :
os.system("curl " + link + " -o " + "%d.mp4" % mp4_index)
elif link.find("pdf") != -1 :
os.system("curl " + link + " -o " + "%d.pdf" % pdf_index)
pdf_index += 1
else :
print "請自行補全下載命令..."
if __name__ == '__main__':
main()
~~~
# 7.完整代碼查看
[Github完整代碼](https://github.com/Andrew-liu/coursera_spider)
- Python爬蟲入門
- (1):綜述
- (2):爬蟲基礎了解
- (3):Urllib庫的基本使用
- (4):Urllib庫的高級用法
- (5):URLError異常處理
- (6):Cookie的使用
- (7):正則表達式
- (8):Beautiful Soup的用法
- Python爬蟲進階
- Python爬蟲進階一之爬蟲框架概述
- Python爬蟲進階二之PySpider框架安裝配置
- Python爬蟲進階三之Scrapy框架安裝配置
- Python爬蟲進階四之PySpider的用法
- Python爬蟲實戰
- Python爬蟲實戰(1):爬取糗事百科段子
- Python爬蟲實戰(2):百度貼吧帖子
- Python爬蟲實戰(3):計算大學本學期績點
- Python爬蟲實戰(4):模擬登錄淘寶并獲取所有訂單
- Python爬蟲實戰(5):抓取淘寶MM照片
- Python爬蟲實戰(6):抓取愛問知識人問題并保存至數據庫
- Python爬蟲利器
- Python爬蟲文章
- Python爬蟲(一)--豆瓣電影抓站小結(成功抓取Top100電影)
- Python爬蟲(二)--Coursera抓站小結
- Python爬蟲(三)-Socket網絡編程
- Python爬蟲(四)--多線程
- Python爬蟲(五)--多線程續(Queue)
- Python爬蟲(六)--Scrapy框架學習
- Python爬蟲(七)--Scrapy模擬登錄
- Python筆記
- python 知乎爬蟲
- Python 爬蟲之——模擬登陸
- python的urllib2 模塊解析
- 蜘蛛項目要用的數據庫操作
- gzip 壓縮格式的網站處理方法
- 通過瀏覽器的調試得出 headers轉換成字典
- Python登錄到weibo.com
- weibo v1.4.5 支持 RSA協議(模擬微博登錄)
- 搭建Scrapy爬蟲的開發環境
- 知乎精華回答的非專業大數據統計
- 基于PySpider的weibo.cn爬蟲
- Python-實現批量抓取妹子圖片
- Python庫
- python數據庫-mysql
- 圖片處理庫PIL
- Mac OS X安裝 Scrapy、PIL、BeautifulSoup
- 正則表達式 re模塊
- 郵件正則
- 正則匹配,但過濾某些字符串
- dict使用方法和快捷查找
- httplib2 庫的使用