Python 爬蟲(chóng)學(xué)習(xí)筆記
學(xué)習(xí)自崔慶才的個(gè)人博客http://www.cnblogs.com/xin-xin/p/4297852.html,以及靜覓http://cuiqingcai.com/
第7章的安裝方法是我自己摸索出來(lái)的,因?yàn)榘凑?strong>崔慶才的文章沒(méi)有安裝成功屋休。
1. Urllib庫(kù)的使用
import urllib2
response = urllib2.urlopen("http://www.baidu.com")
print response.read()
首先我們調(diào)用的是urllib2庫(kù)里面的urlopen方法,傳入一個(gè)URL担忧,這個(gè)網(wǎng)址是百度首頁(yè)缕题,協(xié)議是HTTP協(xié)議沮翔。
urlopen(url, data, timeout)
第一個(gè)參數(shù)url即為URL啥容,第二個(gè)參數(shù)data是訪問(wèn)URL時(shí)要傳送的數(shù)據(jù)秕磷,第三個(gè)timeout是設(shè)置超時(shí)時(shí)間。
response對(duì)象有一個(gè)read方法炼团,可以返回獲取到的網(wǎng)頁(yè)內(nèi)容澎嚣。
其實(shí)上面的urlopen參數(shù)可以傳入一個(gè)request請(qǐng)求,它其實(shí)就是一個(gè)Request類(lèi)的實(shí)例,構(gòu)造時(shí)需要傳入U(xiǎn)rl,Data等等的內(nèi)容.
import urllib2
request = urllib2.Request("http://www.baidu.com")
response = urllib2.urlopen(request)
print response.read()
2.數(shù)據(jù)傳送方式
- post
post方式就是在向服務(wù)器發(fā)送request的時(shí)候?qū)ata數(shù)據(jù)包含其中瘟芝。
import urllib
import urllib2
values = {}
values['username'] = "1016903103@qq.com"
values['password'] = "XXXX"
data = urllib.urlencode(values)
url = "http://passport.csdn.net/account/login易桃?from=http://my.csdn.net/my/mycsdn"
request = urllib2.Request(url,data)
response = urllib2.urlopen(request)
print response.read()
- GET
而GET方式則是直接將data數(shù)據(jù)融入到請(qǐng)求鏈接之中
import urllib
import urllib2
values={}
values['username'] = "1016903103@qq.com"
values['password']="XXXX"
data = urllib.urlencode(values)
url = "http://passport.csdn.net/account/login"
geturl = url + "?"+data
request = urllib2.Request(geturl)
response = urllib2.urlopen(request)
print response.read()
3. Urllib庫(kù)的高級(jí)用法
- 設(shè)置Headers
目的是完全模擬瀏覽器瀏覽網(wǎng)頁(yè)的特征,以防有些網(wǎng)站禁止爬蟲(chóng)程序的運(yùn)行锌俱。
首先是設(shè)置User-Agent
import urllib
import urllib2
url = 'http://www.server.com/login'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
values = {'username' : 'cqc', 'password' : 'XXXX' }
headers = { 'User-Agent' : user_agent }
data = urllib.urlencode(values)
request = urllib2.Request(url, data, headers)
response = urllib2.urlopen(request)
page = response.read()
下來(lái)有對(duì)付反盜鏈的方式晤郑,在headers中加入referer,即將這個(gè)屬性設(shè)置為服務(wù)器自己贸宏。
headers = { 'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' ,
'Referer':'http://www.zhihu.com/articles' }
總之呢造寝,盡量來(lái)模擬真實(shí)瀏覽器的headers的內(nèi)容,構(gòu)建的時(shí)候?qū)懭胪瑯拥臄?shù)據(jù)
- Proxy代理設(shè)置
這個(gè)主要是對(duì)付有的網(wǎng)站會(huì)檢測(cè)IP的訪問(wèn)次數(shù)吭练,次數(shù)過(guò)多诫龙,則會(huì)禁止訪問(wèn),所以設(shè)置代理服務(wù)器鲫咽。
import urllib2
enable_proxy = True
proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080'})
null_proxy_handler = urllib2.ProxyHandler({})
if enable_proxy:
opener = urllib2.build_opener(proxy_handler)
else:
opener = urllib2.build_opener(null_proxy_handler)
urllib2.install_opener(opener)
- 超時(shí)的設(shè)置
urlopen函數(shù)的第三個(gè)參數(shù)是超時(shí)的設(shè)置签赃,它有一個(gè)默認(rèn)參數(shù),因此如果要設(shè)置timeout的話分尸,需要以默認(rèn)參數(shù)的形式設(shè)置timeout=10
import urllib2
response = urllib2.urlopen('http://www.baidu.com', timeout=10)
4. URLError的處理
即是用try except語(yǔ)句來(lái)捕獲異常并加以處理锦聊,其中有一個(gè)小tip是,父類(lèi)的異常應(yīng)當(dāng)寫(xiě)到子類(lèi)異常的后面箩绍,這樣子類(lèi)異常捕獲不到就可以捕獲父類(lèi)異常孔庭。
這里HTTPError是URLError的子類(lèi),因此捕獲異常的代碼可以這么寫(xiě)材蛛,另外加入 hasattr屬性提前對(duì)屬性進(jìn)行判斷史飞,首先對(duì)異常的屬性進(jìn)行判斷尖昏,以免出現(xiàn)屬性輸出報(bào)錯(cuò)的現(xiàn)象:
import urllib2
req = urllib2.Request('http://blog.csdn.net/cqcre')
try:
urllib2.urlopen(req)
except urllib2.HTTPError, e:
if hasattr(e,"code"):
print e.code
except urllib2.URLError, e:
if hasattr(e,"reason"):
print e.reason
else:
print "OK"
5. Cookie的使用
Cookie是網(wǎng)站為了辨別用戶身份,進(jìn)行session跟蹤而存儲(chǔ)到用戶本地終端上的數(shù)據(jù)构资。(加密)
登錄之后才能訪問(wèn)的頁(yè)面抽诉,可以利用Urllib2庫(kù)保存登錄的Cookie,然后再抓取頁(yè)面吐绵。
目的就是模擬登錄的狀態(tài)迹淌。
- opener
前面使用的opener都是默認(rèn)的,使用urlopen來(lái)獲取的己单,相當(dāng)于opener的一個(gè)特殊實(shí)例唉窃,但是使用cookie等高級(jí)功能,必須創(chuàng)建更加一般的opener才能實(shí)現(xiàn)這些功能纹笼。
下面就是使用一個(gè)cookie處理器然后調(diào)用build_opener函數(shù)來(lái)創(chuàng)建一般的opener對(duì)象纹份,然后調(diào)用open方法打開(kāi)url或者request
- 獲取Cookie保存到變量
使用Cookielib模塊,該模塊作用是提供可存儲(chǔ)cookie的對(duì)象廷痘,用CookieJar類(lèi)的對(duì)象捕獲cookie蔓涧。
import urllib2
import cookielib
#這里聲明一個(gè)CookieJar對(duì)象實(shí)例來(lái)保存cookie
cookie=coolielib.CookieJar()
#然后使用urllib2的HTTPCookieProcessor對(duì)象來(lái)創(chuàng)建cookie處理器
handler=urllib2.HTTPCookieProcessor(cookie)
#然后通過(guò)handler來(lái)創(chuàng)建opener
opener=urllib2.build_opener(handler)
#然后調(diào)用opener的open方法,當(dāng)然也可以傳入request
response=opener.open('http://www.baidu.com')
這樣就把cookie保存到變量之中了
- 保存Cookie到文件
則使用FileCookieJar這個(gè)類(lèi)的對(duì)象了笋额,在這里使用MozillaCookieJar對(duì)象
CookieJar —-派生—->FileCookieJar —-派生—–>MozillaCookieJar和LWPCookieJar
cookie的獲取和處理和上面類(lèi)似元暴,只不過(guò)最后調(diào)用了save方法存入之前已經(jīng)傳入MozillaCookieJar的文件里了。
import cookielib
import urllib2
#設(shè)置保存cookie的文件兄猩,同級(jí)目錄下的cookie.txt
filename = 'cookie.txt'
#聲明一個(gè)MozillaCookieJar對(duì)象實(shí)例來(lái)保存cookie茉盏,之后寫(xiě)入文件
cookie = cookielib.MozillaCookieJar(filename)
#利用urllib2庫(kù)的HTTPCookieProcessor對(duì)象來(lái)創(chuàng)建cookie處理器
handler = urllib2.HTTPCookieProcessor(cookie)
#通過(guò)handler來(lái)構(gòu)建opener
opener = urllib2.build_opener(handler)
#創(chuàng)建一個(gè)請(qǐng)求,原理同urllib2的urlopen
response = opener.open("http://www.baidu.com")
#保存cookie到文件
cookie.save(ignore_discard=True, ignore_expires=True)
最后的ignore_discard是即使cookies被丟棄也將其保存下來(lái)枢冤,ignore_exporres是如果cookie文件存在則覆蓋原文件寫(xiě)入鸠姨。
- 從文件中獲取Cookie并訪問(wèn)
先創(chuàng)建MozillaCookie實(shí)例對(duì)象,然后調(diào)用load方法淹真,載入上次生成的文件享怀,接著創(chuàng)建帶有cookie的opener對(duì)象,這里傳入build_opener函數(shù)的是一個(gè)cookie處理器對(duì)象趟咆。和之前的一樣添瓷。
import cookielib
import urllib2
#創(chuàng)建MozillaCookieJar實(shí)例對(duì)象
cookie = cookielib.MozillaCookieJar()
#從文件中讀取cookie內(nèi)容到變量
cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
#創(chuàng)建請(qǐng)求的request
req = urllib2.Request("http://www.baidu.com")
#利用urllib2的build_opener方法創(chuàng)建一個(gè)opener
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
response = opener.open(req)
print response.read()
總之流程就是這樣,創(chuàng)建管理cookie的實(shí)例值纱,鳞贷,創(chuàng)建cookie處理器,創(chuàng)建opener虐唠,然后創(chuàng)建request搀愧,open該request。
- 模擬登錄
這里是先登錄進(jìn)去獲取cookie寫(xiě)入文件,這樣就可以訪問(wèn)登陸后才能訪問(wèn)的頁(yè)面了咱筛。主要是使用了一個(gè)opener對(duì)象搓幌。
import urllib
import urllib2
import cookielib
filename = 'cookie.txt'
#聲明一個(gè)MozillaCookieJar對(duì)象實(shí)例來(lái)保存cookie,之后寫(xiě)入文件
cookie = cookielib.MozillaCookieJar(filename)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
postdata = urllib.urlencode({
'stuid':'201200131012',
'pwd':'23342321'
})
#登錄教務(wù)系統(tǒng)的URL
loginUrl = 'http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bks_login2.login'
#模擬登錄迅箩,并把cookie保存到變量
result = opener.open(loginUrl,postdata)
#保存cookie到cookie.txt中
cookie.save(ignore_discard=True, ignore_expires=True)
#利用cookie請(qǐng)求訪問(wèn)另一個(gè)網(wǎng)址溉愁,此網(wǎng)址是成績(jī)查詢網(wǎng)址
gradeUrl = 'http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bkscjcx.curscopre'
#請(qǐng)求訪問(wèn)成績(jī)查詢網(wǎng)址
result = opener.open(gradeUrl)
print result.read()
一個(gè)處理有驗(yàn)證碼的模擬登錄代碼,不過(guò)暫時(shí)不能成功登錄,原因還不知道為什么饲趋,但是里面表單有一個(gè)lt值每次登錄都在變化拐揭,估計(jì)是因?yàn)檫@個(gè)原因。
#coding=utf-8
import urllib2
import cookielib
import urllib
import re
import sys
'''模擬登錄'''
reload(sys)
sys.setdefaultencoding("utf-8")
# 防止中文報(bào)錯(cuò)
CaptchaUrl = "http://cas.nwpu.edu.cn/cas/Captcha.jpg"
PostUrl = "http://cas.nwpu.edu.cn/cas/login"
# 驗(yàn)證碼地址和post地址
filename="cookies.txt"
cookie = cookielib.MozillaCookieJar(filename)
handler = urllib2.HTTPCookieProcessor(cookie)
opener = urllib2.build_opener(handler)
# 將cookies綁定到一個(gè)opener奕塑,cookie由cookielib自動(dòng)管理
username = '******'
password = '******'
# 用戶名和密碼
picture = opener.open(CaptchaUrl).read()
# 用openr訪問(wèn)驗(yàn)證碼地址,獲取cookie
#文件輸入輸出堂污,local為文件引用句柄
local = open('e:/image.jpg', 'wb')
local.write(picture)
local.close()
# 保存驗(yàn)證碼到本地
SecretCode = raw_input('輸入驗(yàn)證碼: ')
# 打開(kāi)保存的驗(yàn)證碼圖片 輸入
postData = {
'encodedService':'http%3a%2f%2fportal.nwpu.edu.cn%2fdcp%2findex.jsp',
'service':'http://portal.nwpu.edu.cn/dcp/index.jsp',
'serviceName':'null',
'loginErrCnt':'0',
'username': username,
'password': password,
'lt':'LT_nwpuapp1_-527299-2Mb1S8cdQco6UOnf7WNb',
'autoLogin':'false',
'captcha':SecretCode
}
# 根據(jù)抓包信息 構(gòu)造表單
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
'Referer':'http://cas.nwpu.edu.cn/cas/login?service=http%3A%2F%2Fportal.nwpu.edu.cn%2Fdcp%2Findex.jsp'
}
# 根據(jù)抓包信息 構(gòu)造headers
data = urllib.urlencode(postData)
# 生成post數(shù)據(jù) ?key1=value1&key2=value2的形式
request = urllib2.Request(PostUrl, data, headers)
# 構(gòu)造request請(qǐng)求
try:
response = opener.open(request)
cookie.save(ignore_discard=True, ignore_expires=True)
anotherurl='http://portal.nwpu.edu.cn/dcp/forward.action?path=/portal/portal&p=HomePage'
response = opener.open(anotherurl)
result = response.read()
print result
# 打印登錄后的頁(yè)面
except urllib2.HTTPError, e:
print e.code
# 利用之前存有cookie的opener登錄頁(yè)面
6. 正則表達(dá)式
對(duì)字符串進(jìn)行過(guò)濾,Python里的數(shù)量詞默認(rèn)是貪婪的龄砰,匹配盡可能多的字符盟猖,不過(guò)一般使用非貪婪模式進(jìn)行提取,换棚?是一個(gè)非貪婪字符式镐。
反斜杠問(wèn)題將使用原生字符串解決,比如匹配\圃泡,則使用這樣的正則表達(dá)式:r"\"
這個(gè)問(wèn)題得實(shí)踐驗(yàn)證碟案,因?yàn)樵赑ython核心編程里有這么一個(gè)pattern來(lái)進(jìn)行匹配的:
patt='\w+@(\w+\.)?\w+\.com'
這個(gè)是匹配一個(gè)電子郵件地址的愿险,@之前是匹配至少一個(gè)字符或者數(shù)字的字符颇蜡,之后是進(jìn)行分組,匹配添加主機(jī)名稱(chēng)辆亏,然后是域名风秤。
這里\也沒(méi)說(shuō)受到什么影響,因此實(shí)踐是檢驗(yàn)真理的唯一選擇扮叨。
- Python里的Re模塊
首先在進(jìn)行匹配之前缤弦,最好使用compile()函數(shù)進(jìn)行預(yù)編譯,預(yù)編譯之后是返回regex對(duì)象彻磁,再使用re模塊里面的方法即可完成匹配碍沐。
如果沒(méi)有進(jìn)行預(yù)編譯的話,則使用的是re模塊里面的函數(shù)衷蜓,函數(shù)名與作用與上述方法是一致的累提。
compile()用法如下:pattern=re.compile(r'hello')
另外除了regex對(duì)象,還有另外一種對(duì)象類(lèi)型磁浇,匹配對(duì)象斋陪,是match或者search被成功調(diào)用后返回的結(jié)果,有兩個(gè)主要的方法是group和groups
group方法返回所有匹配對(duì)象或者是根據(jù)要求返回某個(gè)特定子組
groups方法是返回一個(gè)包含唯一或者所有子組的元組
- re模塊里面的函數(shù)與方法
match(pattern,string,flags=0)
使用正則表達(dá)式匹配string,是從字符串開(kāi)頭開(kāi)始匹配无虚,失敗則返回None
一個(gè)匹配實(shí)例缔赠,最后一個(gè)匹配子組是給該子組取了個(gè)別名sign,它的作用就是匹配S烟狻(任意字符)嗤堰。
import re
# 匹配如下內(nèi)容:?jiǎn)卧~+空格+單詞+任意字符
m = re.match(r'(\w+) (\w+)(?P<sign>.*)', 'hello world!')
re.search(pattern,string,flags=0)
search()是搜索字符串中模式首次出現(xiàn)的位置,是在任意位置而不是嘗試在起始處匹配咆爽。
import re
# 將正則表達(dá)式編譯成Pattern對(duì)象
pattern = re.compile(r'world')
# 使用search()查找匹配的子串梁棠,不存在能匹配的子串時(shí)將返回None
# 這個(gè)例子中使用match()無(wú)法成功匹配
match = re.search(pattern,'hello world!')
if match:
# 使用Match獲得分組信息
print match.group()
### 輸出 ###
# world
re.findall(pattern,string[,flags])
搜索string,以列表形式返回全部能匹配的子串斗埂。
import re
pattern = re.compile(r'\d+')
print re.findall(pattern,'one1two2three3four4')
### 輸出 ###
# ['1', '2', '3', '4']
re.split(pattern,string[,maxsplit])
使用了正則表達(dá)式的split方法將成為一個(gè)功能更為強(qiáng)大的工具符糊。maxsplit指定最大分隔次數(shù),不指定則全部分隔呛凶。
import re
pattern = re.compile(r'\d+')
print re.split(pattern,'one1two2three3four4')
### 輸出 ###
# ['one', 'two', 'three', 'four', '']
re.sub(pattern,repl,string,max=0)
使用repl替換string中所有被正則表達(dá)式匹配的地方男娄,max最大替換次數(shù),如果不指定則將所有替換漾稀。當(dāng)repl是一個(gè)字符串時(shí)模闲,可以使用\id或\g、\g引用分組崭捍,但不能使用編號(hào)0尸折。
import re
pattern = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print re.sub(pattern,r'\2 \1', s)
### output ###
# say i, world hello!
另外subn方法將返回替換次數(shù),替換后的字符串和表示替換次數(shù)的數(shù)字作為一個(gè)元組的元素返回殷蛇。
### output ###
# ('say i, world hello!', 2)
7. 爬蟲(chóng)框架Scrapy的安裝與配置
- 安裝Python
這個(gè)自不必說(shuō)实夹,安裝完最重要的是將Python安裝文件夾和底下的Scripts文件夾加入環(huán)境變量,這樣cmd命令行就可以直接執(zhí)行Python命令了粒梦。
- 安裝pywin32
安裝地址:http://sourceforge.net/projects/pywin32/
安裝完進(jìn)入Python執(zhí)行環(huán)境亮航,輸入import win32com
如果沒(méi)有錯(cuò)誤則安裝成功。
- 安裝pyOPENSSL
下載地址:https://launchpad.net/pyopenssl
下載下來(lái)之后拷貝到Python根目錄下的Scripts文件夾里匀们,然后在cmd命令里進(jìn)入到Scripts文件夾缴淋,執(zhí)行easy_install.exe pyOpenSSL-0.11-py3.2-win32.egg
就可以進(jìn)行安裝了。
或者是在Scripts文件夾下執(zhí)行easy_install pyOpenSSL
cryptography
或者是下載可執(zhí)行安裝文件進(jìn)行安裝泄朴,在打開(kāi)的頁(yè)面找到all downloads然后找到pyOpenSSL-0.11.winxp32-py2.7.exe,直接點(diǎn)擊該鏈接可以下載Python2.7的重抖,如果需要其他版本前往該網(wǎng)站下載。
同樣安裝完成后在Python環(huán)境里執(zhí)行import OpenSSL
驗(yàn)證是否安裝成功祖灰。
pyOpenSSL出錯(cuò)解決嘗試
首先安裝了Twisted钟沛,easy_install Twisted
,還是不行夫植。
下來(lái)安裝了cffi,easy_install cffi
讹剔,提示VC++9.0for Python命令錯(cuò)誤
然后下載了VC++9.0 for python油讯,發(fā)現(xiàn)電腦已經(jīng)安裝過(guò)了,仍然沒(méi)有解決延欠。
然后看到槍桿子的博客文章陌兑,Windows7 (64位)系統(tǒng)下安裝Scrapy詳細(xì)教程,他將所有需要的依賴(lài)打包到百度網(wǎng)盤(pán)里了由捎,然后正在下載的時(shí)候兔综,網(wǎng)絡(luò)沒(méi)流量了,只能等到下午充了之后再下載試試了狞玛。
根據(jù)他的文章所述软驰,要安裝Scrapy框架,必須安裝如下依賴(lài):
lxml,pywin32,Twisted,pyOpenSSL,zope.interface
回來(lái)下載好這些文件心肪,但是安裝時(shí)候報(bào)錯(cuò)沒(méi)有找到Python2.7可是我裝的就是Python2.7锭亏,不解,然后又按照之前的教程去下載了pyOpenSSL for Python2.7硬鞍,執(zhí)行easy_install.exe pyOpenSSL-0.11-py2.7-win32.egg
然后居然好了慧瘤,pyOpenSSL安裝成功。
- 安裝lxml
一個(gè)Python庫(kù)固该,可以迅速靈活的處理xml
pip install lxml
進(jìn)行安裝或者easy_install lxml
- 安裝Scrapy
最后一步就是安裝Scrapy框架锅减。
pip install Scrapy
或者easy_install Scrapy
驗(yàn)證一下,輸入Scrapy伐坏,即可驗(yàn)證是否成功怔匣。
7.1 安裝依賴(lài)文件tips:
再看了個(gè)教程,直接在官網(wǎng)上下載對(duì)應(yīng)需要的依賴(lài)文件(.egg格式),然后下載下來(lái)使用easy_install來(lái)安裝桦沉,直接就搞定每瞒,如果通過(guò)網(wǎng)絡(luò)自動(dòng)下載安裝,會(huì)出現(xiàn)各種問(wèn)題永部。在這里將所有依賴(lài)文件以及鏈接歸納如下:
選擇對(duì)應(yīng)版本下載安裝独泞,這里都是可執(zhí)行文件呐矾,直接點(diǎn)擊安裝苔埋。
選擇.egg格式的文件下載,下載之后放到Python根目錄下的Scripts文件夾里蜒犯,進(jìn)入CMD執(zhí)行easy_install 文件名即可完成安裝组橄。
Twisted:
easy_install Twisted
cffi:
easy_install cffi
lxml:
easy_install lxml
cryptography:https://pypi.python.org/pypi/cryptography
選擇對(duì)應(yīng)Python版本,同pyOpenSSL安裝方法罚随。
zope.interface:
easy_install zope.interface
最后一步就是安裝Scrapy框架玉工。
pip install Scrapy
或者easy_install Scrapy