urllib是基于http的高層庫娇钱,它有以下三個主要功能:
(1)request處理客戶端的請求
(2)response處理服務(wù)端的響應(yīng)
(3)parse會解析url
一网梢、爬取網(wǎng)頁內(nèi)容
我們知道,網(wǎng)頁上呈現(xiàn)的優(yōu)美頁面增热,本質(zhì)都是一段段的HTML代碼填硕,加上JS 、CSS等缕陕,本人也是剛開始學(xué)python,這個文章也比較小白疙挺,資深老鳥請忽略~~扛邑。
本文所說的代碼都是基于python3的,使用phython2的請注意
python 3.x中urllib庫和urilib2庫合并成了urllib庫
其中urllib2.urlopen()變成了urllib.request.urlopen()
urllib2.Request()變成了urllib.request.Request()
那么獲取網(wǎng)頁有哪一些方法呢铐然?這里列舉了三種方法蔬崩,具體查看代碼。
import urllib.request
import http.cookiejar
url = 'http://www.baidu.com'
#直接通過url來獲取網(wǎng)頁數(shù)據(jù)
print('第一種 :直接通過url來獲取網(wǎng)頁數(shù)據(jù)')
response = urllib.request.urlopen(url)
html = response.read()
mystr = html.decode("utf8")
response.close()
print(mystr)
#構(gòu)建request對象進行網(wǎng)頁數(shù)據(jù)獲取
print('第二種 :構(gòu)建request對象進行網(wǎng)頁數(shù)據(jù)獲取')
request = urllib.request.Request(url)
request.add_header('user-agent', 'Mozilla/5.0')
response2 = urllib.request.urlopen(request)
html2 = response2.read()
mystr2 = html2.decode("utf8")
response2.close()
print(mystr2)
#使用cookies來獲取 需要import http.cookiejar
print('第三種:使用cookies來獲取')
cj = http.cookiejar.LWPCookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
urllib.request.install_opener(opener)
response3 = urllib.request.urlopen(url)
print(cj)
html3 = response3.read()
mystr3 = html3.decode("utf8")
response3.close()
print(mystr3)
將上面的代碼copy之后搀暑,在pycharm新建一個python項目舱殿,如下圖,新建一個python file 险掀,命名為demo.py 黏貼上面的代碼
右鍵運行改文件沪袭,我們就可以從控制臺獲取到整個網(wǎng)頁內(nèi)容了
或者打開pycharm的terminal窗口,輸入
python demo.py
copy上面網(wǎng)頁內(nèi)容樟氢,然后黏貼到下面的在線HTML 運行工具
http://www.5axxw.com/tools/web/web_run.html
運行之后我們可以看到下圖網(wǎng)址部分是本地的冈绊,對比網(wǎng)頁的百度,發(fā)現(xiàn)底部的那些網(wǎng)頁新聞不見了埠啃,因為我們抓取的是靜態(tài)網(wǎng)頁呀死宣,動態(tài)網(wǎng)頁需要的一些參數(shù),要如何傳遞給他碴开,下面有簡單的解釋毅该。利用這個我們也可以只抓取我們需要的靜態(tài)網(wǎng)頁,相當(dāng)于做了一些去廣告之類的潦牛。眶掌。。巴碗。朴爬。
從代碼看出,上面使用的urlopen方法橡淆,傳入一個URL召噩,這個網(wǎng)址是百度首頁,協(xié)議是HTTP協(xié)議逸爵,當(dāng)然你也可以把HTTP換做FTP,FILE,HTTPS 等等具滴,只是代表了一種協(xié)議,urlopen一般接受三個參數(shù)师倔,它的參數(shù)如下:
urlopen(url, data, timeout)
第一個參數(shù)url即為URL构韵,第二個參數(shù)data是訪問URL時要傳送的數(shù)據(jù),第三個timeout是設(shè)置超時時間。
第二三個參數(shù)是可以不傳送的贞绳,data默認為空None谷醉,timeout默認為 socket._GLOBAL_DEFAULT_TIMEOUT
第一個參數(shù)URL是必須要傳送的,在這個例子里面我們傳送了百度的URL冈闭,執(zhí)行urlopen方法之后俱尼,返回一個response對象,返回信息便保存在這里面萎攒。
response.read()
response對象有一個read方法遇八,可以返回獲取到的網(wǎng)頁內(nèi)容,我們可以的到一個HTML格式的文檔耍休。
二刃永、構(gòu)造Request
其實上面的urlopen參數(shù)也可以傳入一個Request類的實例,我們構(gòu)造request時需要傳入Url,Data等等的內(nèi)容羊精。
import urllib.request
req = urllib.request.Request('http://python.org/')
response = urllib.request.urlopen(req)
the_page = response.read()
三斯够、發(fā)送數(shù)據(jù)
http協(xié)議有六種請求方法,get,head,put,delete,post,options喧锦,數(shù)據(jù)傳送最基本的就是POST和GET兩種方式读规,其他方式這里也不進行擴展。
這里我們結(jié)合CSDN的登錄進行介紹
打開以下網(wǎng)頁 https://passport.csdn.net/account/login?from=http://my.csdn.net/my/mycsdn 我們可以看到需要我們輸入一個是賬號燃少,一個是密碼束亏。
點擊登錄之后,網(wǎng)頁就是利用post的方式阵具,把上面兩個輸入項作為參數(shù)碍遍,動態(tài)的發(fā)送過去了。
import urllib.parse
import urllib.request
values = {}
values['username'] = "XXXXXXX@qq.com"
values['password'] = "XXXXXXX"
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
headers = {'User-Agent': user_agent}
data = urllib.parse.urlencode(values).encode('UTF8')//這里不encode會類型報錯
url = "https://passport.csdn.net/account/login?from=http://my.csdn.net/my/mycsdn"
request = urllib.request.Request(url, data, headers)
response = urllib.request.urlopen(request)
the_page = response.read()
print(the_page.decode("utf8"))
運行之后我們發(fā)現(xiàn)又跳回了登錄界面阳液,里面我們看到返回網(wǎng)頁中有這么一段注釋:
<!-- 該參數(shù)可以理解成每個需要登錄的用戶都有一個流水號怕敬。只有有了webflow發(fā)放的有效的流水號,用戶才可以說明是已經(jīng)進入了webflow流程趁舀。否則赖捌,沒有流水號的情況下祝沸,webflow會認為用戶還沒有進入webflow流程
矮烹,從而會重新進入一次webflow流程,從而會重新出現(xiàn)登錄界面罩锐。 -->
<input type="hidden" name="lt" value="LT-481574-sCMBpUSfbcMhRTP5imPR5ir9dd0Ett" />
<input type="hidden" name="execution" value="e1s1" />
<input type="hidden" name="_eventId" value="submit" />
于是我們需要添加這個參數(shù)奉狈,然后登錄就成功了,請看代碼
import urllib.parse, urllib.request, http.cookiejar, re
cookie = http.cookiejar.CookieJar()
cookieProc = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(cookieProc)
h = opener.open('https://passport.csdn.net').read().decode("utf8")
patten1 = re.compile(r'name="lt" value="(.*?)"')
patten2 = re.compile(r'name="execution" value="(.*?)"')
b1 = patten1.search(h)
b2 = patten2.search(h)
postData = {
'username': 'csdn用戶名',
'password': 'csdn密碼',
'lt': b1.group(1),
'execution': b2.group(1),
'_eventId': 'submit',
}
postData = urllib.parse.urlencode(postData).encode('UTF8')
opener.addheaders = [('Origin', 'https://passport.csdn.net'),
('User-Agent',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36'),
('Referer', 'https://passport.csdn.net/account/login?from=http://my.csdn.net/my/mycsdn')
]
response = opener.open('https://passport.csdn.net', postData)
text = response.read().decode('utf-8', 'ignore')
print(text)
response2 = opener.open('http://my.csdn.net/my/mycsdn')
text2 = response2.read().decode('utf-8', 'ignore')
print(text2)
GET方式:
上面我們使用的是post的形式的涩惑,至于GET方式區(qū)別就是在URL上仁期,我們?nèi)绻苯影褏?shù)寫到網(wǎng)址上面,構(gòu)建一個帶參數(shù)的URL。
values={}
values['username'] = "XXXXX@qq.com"
values['password']="XXXX"
data = urllib.parse.urlencode(values)
url = "http://passport.csdn.net/account/login"
geturl = url + "?"+data
使用 HTTP 的 PUT 和 DELETE 方法
有時候需要用到PUT方式或者DELETE方式請求跛蛋。
PUT:這個方法比較少見熬的。HTML表單也不支持這個。本質(zhì)上來講赊级, PUT和POST極為相似押框,都是向服務(wù)器發(fā)送數(shù)據(jù),但它們之間有一個重要區(qū)別理逊,PUT通常指定了資源的存放位置橡伞,而POST則沒有,POST的數(shù)據(jù)存放位置由服務(wù)器自己決定晋被。
DELETE:刪除某一個資源兑徘。基本上這個也很少見羡洛,不過還是有一些地方比如amazon的S3云服務(wù)里面就用的這個方法來刪除資源挂脑。
如果要使用 HTTP PUT 和 DELETE ,只能使用比較低層的 httplib 庫欲侮。雖然如此最域,我們還是能通過下面的方式,使 urllib 能夠發(fā)出 PUT 或DELETE 的請求锈麸,不過用的次數(shù)的確是少镀脂,在這里提一下。
import urllib.request
request = urllib.request.Request(uri, data=data)
request.get_method = lambda: 'PUT' # or 'DELETE'
response = urllib.request.urlopen(request)
四忘伞、添加頭部
我們知道薄翅,很多網(wǎng)站,如果不設(shè)置請求頭部屬性氓奈,根本就不會得到響應(yīng)翘魄,而且有一些還要求匹配頭部的某些屬性,所以我們需要去模擬正常訪問的頭部設(shè)置舀奶。那么我們怎么獲取這個headers的屬性呢暑竟?
這個需要借助我們的Chrome瀏覽器了络它。F12打開你需要爬取的網(wǎng)頁幔荒,打開網(wǎng)絡(luò)監(jiān)聽
起初右邊是沒有多少信息的,然后點擊登錄彼城,我們可以看到捕獲到了很多信息涧至,我們選取第一個腹躁,點擊header,就可以查看到我們需要的一些信息了南蓬。具體headers各個屬性的作用纺非,請參閱Http Headers各屬性的作用
其中哑了,agent就是請求的身份,如果沒有寫入請求身份烧颖,那么服務(wù)器不一定會響應(yīng)弱左,所以可以在headers中設(shè)置agent,當(dāng)我們設(shè)置leheaders炕淮,在構(gòu)建request時傳入科贬,到了請求時,就會加入headers傳送鳖悠,服務(wù)器若識別了是瀏覽器發(fā)來的請求榜掌,就會得到響應(yīng)。
另外乘综,我們還有對付”反盜鏈”的方式憎账,對付防盜鏈,服務(wù)器會識別headers中的referer是不是它自己卡辰,如果不是胞皱,有的服務(wù)器不會響應(yīng),所以我們還可以在headers中加入referer
cookie = http.cookiejar.CookieJar()
cookieProc = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(cookieProc)
opener.addheaders = [('Origin', 'https://passport.csdn.net'),
('User-Agent',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36'),
('Referer', '需要添加頭部的網(wǎng)址')
]
五九妈、http 錯誤
import urllib.request
req = urllib.request.Request(' ')
try:
urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
print(e.code)
print(e.read().decode("utf8"))
六反砌、異常處理
except HTTPError as e:
except URLError as e:
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
req = Request("http://www..net /")
try:
response = urlopen(req)
except HTTPError as e:
print('The server couldn't fulfill the request.')
print('Error code: ', e.code)
except URLError as e:
print('We failed to reach a server.')
print('Reason: ', e.reason)
else:
print("good!")
print(response.read().decode("utf8"))
except URLError as e:
if hasattr(e, 'reason'):
elif hasattr(e, 'code'):
from urllib.request import Request, urlopen
from urllib.error import URLError
req = Request("http://www.Python.org/")
try:
response = urlopen(req)
except URLError as e:
if hasattr(e, 'reason'):
print('We failed to reach a server.')
print('Reason: ', e.reason)
elif hasattr(e, 'code'):
print('The server couldn't fulfill the request.')
print('Error code: ', e.code)
else:
print("good!")
print(response.read().decode("utf8"))
七、HTTP 認證
import urllib.request
# create a password manager
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
# Add the username and password.
# If we knew the realm, we could use it instead of None.
top_level_url = ""
password_mgr.add_password(None, top_level_url, 'rekfan', 'xxxxxx')
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
# create "opener" (OpenerDirector instance)
opener = urllib.request.build_opener(handler)
# use the opener to fetch a URL
a_url = ""
x = opener.open(a_url)
print(x.read())
# Install the opener.
# Now all calls to urllib.request.urlopen use our opener.
urllib.request.install_opener(opener)
a = urllib.request.urlopen(a_url).read().decode('utf8')
print(a)
八萌朱、使用代理
urllib 默認會使用環(huán)境變量 http_proxy 來設(shè)置 HTTP Proxy宴树。假如一個網(wǎng)站它會檢測某一段時間某個IP 的訪問次數(shù),如果訪問次數(shù)過多晶疼,它會禁止你的訪問酒贬。所以你可以設(shè)置一些代理服務(wù)器來幫助你做工作,每隔一段時間換一個代理翠霍,網(wǎng)站君都不知道是誰在搗鬼了锭吨!
下面一段代碼說明了代理的設(shè)置用法
import urllib.request
enable_proxy = True
proxy_support = urllib.request.ProxyHandler({'sock5': 'localhost:1080'})
null_proxy_handler = urllib.request.ProxyHandler({})
if enable_proxy:
opener = urllib.request.build_opener(proxy_support)
else:
opener = urllib.request.build_opener(null_proxy_handler)
urllib.request.install_opener(opener)
a = urllib.request.urlopen("").read().decode("utf8")
print(a)
九、超時
import socket
import urllib.request
# timeout in seconds
timeout = 2
socket.setdefaulttimeout(timeout)
# this call to urllib.request.urlopen now uses the default timeout
# we have set in the socket module
req = urllib.request.Request('')
a = urllib.request.urlopen(req).read()
print(a)
上面已經(jīng)說過urlopen方法了寒匙,第三個參數(shù)就是timeout的設(shè)置零如,可以設(shè)置等待多久超時,為了解決一些網(wǎng)站實在響應(yīng)過慢而造成的影響锄弱。
例如下面的代碼,如果第二個參數(shù)data為空那么要特別指定是timeout是多少考蕾,寫明形參。
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com', timeout=10)
如果data已經(jīng)傳入棵癣,則不必聲明辕翰。
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com',data, 10)