urllib 是 Python 內(nèi)置的 HTTP 請(qǐng)求庫(kù),它包含四個(gè)模塊:
1.發(fā)送請(qǐng)求
2.處理異常模塊
3.parse解析模塊的使用
4.Handler處理器 和 自定義Opener
5.robot協(xié)議介紹
1)發(fā)送請(qǐng)求之get方法
GET請(qǐng)求一般用于我們向服務(wù)器獲取數(shù)據(jù)
爬取網(wǎng)頁(yè):
導(dǎo)入模塊:
import urllib.request
import re
class NeiHan():
def __init__(self):
#定位爬的url地址
self.url = 'http://www.neihan8.com/wenzi//'
#請(qǐng)求頭
self.headers = {
'User-Agent': "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0"
}
def loadpage(self, url):
# 構(gòu)建request
request = urllib.request.Request(url=self.url, headers=self.headers)
# 發(fā)起請(qǐng)求
response = urllib.request.urlopen(request)
# 內(nèi)容編碼
content = response.read().decode()
#正則:
pattern = re.compile(r'<div.*?class="desc">(.*?)</div>', re.S)
#提取內(nèi)容
neihan_list = pattern.findall(content)
#內(nèi)容寫入
for neihan in neihan_list:
self.writepage(neihan)
#寫入到neihan.txt文件
def writepage(self, neihan):
with open('neihan.txt', 'a') as f:
f.write(neihan + '\n')
if __name__ == '__main__':
c = NerHan()
c.loadpage()
2)發(fā)送請(qǐng)求之post方法
Request請(qǐng)求對(duì)象的里有data參數(shù)殃姓,它就是用在POST里的望伦,我們要傳送的數(shù)據(jù)就是這個(gè)參數(shù)data,data是一個(gè)字典豁状,里面要匹配鍵值對(duì)。
import urllib.request
#工具
import urllib.parse
#請(qǐng)求頭
headers = {
'User-Agent': 'Mozilla / 5.0(X11;Ubuntu;Linuxx86_64;rv: 54.0) Gecko / 20100101Firefox / 54.0'
}
#測(cè)試
url = 'https://httpbin.org/post'
#構(gòu)建post請(qǐng)求的表單數(shù)據(jù)
data = {
'name': 'xiaohu',
'age': 20
}
#將參數(shù)轉(zhuǎn)為url編碼格式,并轉(zhuǎn)為bytes類型的數(shù)據(jù)
params = urllib.parse.urlencode(data).encode()
#構(gòu)建request
request = urllib.request.Request(url=url, data=params, headers=headers)
#發(fā)起請(qǐng)求獲取響應(yīng)結(jié)果
response = urllib.request.urlopen(request)
content = response.read().decode()
print(content)
GET方式是直接以鏈接形式訪問(wèn),鏈接中包含了所有的參數(shù)出革,服務(wù)器端用Request.QueryString獲取變量的值。如果包含了密碼的話是一種不安全的選擇覆履,不過(guò)你可以直觀地看到自己提交了什么內(nèi)容蹋盆。
POST則不會(huì)在網(wǎng)址上顯示所有的參數(shù)费薄,服務(wù)器端用Request.Form獲取提交的數(shù)據(jù)硝全,在Form提交的時(shí)候。但是HTML代碼里如果不指定 method 屬性楞抡,則默認(rèn)為GET請(qǐng)求伟众,F(xiàn)orm中提交的數(shù)據(jù)將會(huì)附加在url之后,以?分開與url分開召廷。
url.parse :定義了url的標(biāo)準(zhǔn)接口凳厢,實(shí)現(xiàn)url的各種抽取
parse模塊的使用:url的解析账胧,合并,編碼先紫,解碼
import urllib.parse
url = 'https://book.qidian.com/info/1004608738?wd=123&page=20#Catalog'
# 把URL拆開
print(urllib.parse.urlparse(url))
url_parmas = ('https', 'book.qidian.com', '/info/1004608738', '', 'wd=123&page=20', 'Catalog')
print(urllib.parse.urlunparse(url_parmas))
#將某一個(gè)不完整的鏈接拼接為一個(gè)完整鏈接
base_url = 'https://book.qidian.com/info/1004608738?wd=123&page=20#Catalog'
sub_url = '/info/100861102'
print(urllib.parse.urljoin(base_url,sub_url))
#將字典形式的參數(shù)序列化為url編碼后的字符串
#urllib.parse.urlencode()
parmas_str = 'page=20&wd=123'
parmas = urllib.parse.parse_qs(parmas_str)
print(parmas)
#將中文轉(zhuǎn)換為URL編碼格式
word = '中國(guó)夢(mèng)'
url = 'http://www.baidu.com/s?wd='+urllib.parse.quote(word)
print(urllib.parse.quote(word))
print(url)
#將URL編碼進(jìn)行解碼
url = 'http://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD%E6%A2%A6'
print(urllib.parse.unquote(url))
urllib 的異常錯(cuò)誤處理
我們?cè)诎l(fā)送請(qǐng)求的過(guò)程中治泥,如果網(wǎng)絡(luò)環(huán)境不好,或者出現(xiàn)了其他問(wèn)題遮精,會(huì)出現(xiàn)請(qǐng)求異常居夹,如果不處理這些異常,程序很可能會(huì)崩潰本冲,所以我們需要處理請(qǐng)求異常問(wèn)題.
這里主要說(shuō)的是URLError和HTTPError准脂,以及對(duì)它們的錯(cuò)誤處理。
URLError:來(lái)自u(píng)rllib庫(kù)的error模塊檬洞,繼承自O(shè)SError,由request模塊產(chǎn)生的異常都可以通過(guò)捕捉這個(gè)類來(lái)處理.
產(chǎn)生的原因主要有:
- 沒(méi)有網(wǎng)絡(luò)連接
2.服務(wù)器連接失敗 - 找不到指定的服務(wù)器
它具有一個(gè)屬性reason,返回錯(cuò)誤的原因
import urllib.error
import urllib.request
try:
urllib.request.urlopen('http://www.baidu.com',timeout=0.01)
except urllib.error.URLError as e:
print(e.reason)
try:
urllib.request.urlopen('https://www.qidian.com/all/nsacnscn.htm')
except urllib.error.HTTPError as e:
print(e.reason)
print(e.code)
print(e.headers)
try:
urllib.request.urlopen('https://www.qidian.com/all/nsacnscn.htm')
except Exception as e:
print(e)
常見(jiàn)的HTTP狀態(tài)碼:
200 - 請(qǐng)求成功
301 - 資源(網(wǎng)頁(yè)等)被永久轉(zhuǎn)移到其它URL
302 - 資源(網(wǎng)頁(yè)等)被臨時(shí)轉(zhuǎn)移到其它URL
401 - 未授權(quán)
403 - 禁止訪問(wèn)
408 - 請(qǐng)求超時(shí)
404 - 請(qǐng)求的資源(網(wǎng)頁(yè)等)不存在
500 - 內(nèi)部服務(wù)器錯(cuò)誤
503 - 服務(wù)器不可用
基本的urlopen()方法不支持代理狸膏、cookie等其他的HTTP/HTTPS高級(jí)功能。所以要支持這些功能:
使用相關(guān)的 Handler處理器 來(lái)創(chuàng)建特定功能的處理器對(duì)象添怔;
然后通過(guò) urllib.request.build_opener()方法使用這些處理器對(duì)象湾戳,創(chuàng)建自定義opener對(duì)象;
使用自定義的opener對(duì)象广料,調(diào)用open()方法發(fā)送請(qǐng)求院塞。
import urllib.request
url = "http://www.baidu.com"
# 處理http請(qǐng)求 ctrl+shift+u 大寫變小寫
httphandler = urllib.request.HTTPHandler(debuglevel=1)
# 處理https請(qǐng)求的handler
# httpshandler = urllib.request.HTTPsHandler()
# 第二步 創(chuàng)建一個(gè)opener
opener = urllib.request.build_opener(httphandler)
# 創(chuàng)建一個(gè)請(qǐng)求
request = urllib.request.Request(url=url)
# 發(fā)送請(qǐng)求
# urllib.request.urlopen(request)這是原來(lái)的發(fā)送請(qǐng)求方法
response = opener.open(request)
# 讀取數(shù)據(jù)
content = response.read().decode()
with open('baidu.html', 'w') as f:
f.write(content)
代理:
基本原理: 代理實(shí)際上指的就是代理服務(wù)器,英文叫作proxy server性昭,它的功能是代理網(wǎng)絡(luò)用戶去取得網(wǎng)絡(luò)信息拦止。形象地說(shuō),它是網(wǎng)絡(luò)信息的中轉(zhuǎn)站糜颠。在我們正常請(qǐng)求一個(gè)網(wǎng)站時(shí)汹族,其實(shí)是發(fā)送了請(qǐng)求給Web服務(wù)器,Web服務(wù)器把響應(yīng)傳回給我們其兴。如果設(shè)置了代理服務(wù)器顶瞒,實(shí)際上就是在本機(jī)和服務(wù)器之間搭建了一個(gè)橋,此時(shí)本機(jī)不是直接向Web服務(wù)器發(fā)起請(qǐng)求元旬,而是向代理服務(wù)器發(fā)出請(qǐng)求榴徐,請(qǐng)求會(huì)發(fā)送給代理服務(wù)器,然后由代理服務(wù)器再發(fā)送給Web服務(wù)器匀归,接著由代理服務(wù)器再把Web服務(wù)器返回的響應(yīng)轉(zhuǎn)發(fā)給本機(jī)坑资。這樣我們同樣可以正常訪問(wèn)網(wǎng)頁(yè),但這個(gè)過(guò)程中Web服務(wù)器識(shí)別出的真實(shí)IP就不再是我們本機(jī)的IP了穆端,就成功實(shí)現(xiàn)了IP偽裝袱贮,這就是代理的基本原理
代理的作用:
1.突破自身IP訪問(wèn)限制
2.訪問(wèn)一些單位或團(tuán)體內(nèi)部資源
3.提高訪問(wèn)速度
4.隱藏真實(shí)IP
1.根據(jù)協(xié)議劃分:
FTP代理服務(wù)器
HTTP代理服務(wù)器
SSL/TLS代理
SOCKS代理
根據(jù)匿名內(nèi)容劃分:
高度匿名代理
普通匿名代理
透明代理
import urllib.request
import urllib.parse
# 免費(fèi)代理
# proxy = {
# 'http': '61.176.223.7:58822',
# 'https': '218.76.253.201:61408',
# }
# 構(gòu)建一個(gè)私密代理Handler,需要加上私密代理賬戶的用戶名和密碼
authproxy = {
"https": "496155678:tx4p1gbw@112.74.108.33:16817",
# "http": "496155678:tx4p1gbw@112.74.108.33:16817"
}
# 創(chuàng)建處理代理的handler
proxyhandler = urllib.request.ProxyHandler(
proxies = authproxy
)
# 創(chuàng)建一個(gè)opener
opener = urllib.request.build_opener(proxyhandler)
# 構(gòu)造一個(gè)請(qǐng)求
# request = urllib.request.Request(url='http://www.baidu.com')
# 發(fā)送請(qǐng)求
# response = opener.open(request)
url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0',
'Referer': 'https://www.lagou.com/jobs/list_java?labelWords=&fromSearch=true&suginput=?labelWords=hot',
'X-Requested-With': 'XMLHttpRequest',
'Origin': 'https://www.lagou.com',
'Cookie': '_ga=GA1.2.454842362.1523882199; user_trace_token=20180416203639-cf8fa21d-4172-11e8-87b1-525400f775ce; LGUID=20180416203639-cf8fa4c6-4172-11e8-87b1-525400f775ce; _gid=GA1.2.357008350.1545287354; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22166af40632b7e4-0d1fb84d73b02a-346e780b-1024000-166af40632c733%22%2C%22%24device_id%22%3A%22166af40632b7e4-0d1fb84d73b02a-346e780b-1024000-166af40632c733%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D; showExpriedIndex=1; showExpriedCompanyHome=1; showExpriedMyPublish=1; hasDeliver=66; index_location_city=%E5%85%A8%E5%9B%BD; JSESSIONID=ABAAABAAAFCAAEG69A81B4AAC041DE1DF146C1C4175134C; _gat=1; LGSID=20181221104450-63482a8c-04ca-11e9-9f54-5254005c3644; PRE_UTM=; PRE_HOST=www.baidu.com; PRE_SITE=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3D_T_xi2Zd5W1_6G3zKFKezYvVu0lSBC5FQIr4HeQYOEa%26wd%3D%26eqid%3Dbdffabc60000f773000000025c1c5397; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1545303897,1545303905,1545352391,1545360291; LG_LOGIN_USER_ID=2d426d30feeb0777f3fc1657c0ea320fe465c87ef5bbbe5e; _putrc=42E0B5E87AD73B68; login=true; unick=%E8%B5%B5%E5%BA%86%E5%85%83; SEARCH_ID=94e60c5736f746ca915c2fad34993630; LGRID=20181221105414-b345f6f4-04cb-11e9-87ca-525400f775ce; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1545360856; TG-TRACK-CODE=index_hotsearch; gate_login_token=275f6c1c24a8e56f015e157826f0c802878a39df65bfedc1',
}
data = {
'first': 'false',
'pn': 2,
'kd': 'java'
}
# 傳遞的數(shù)據(jù)要進(jìn)行二進(jìn)制編碼
params = urllib.parse.urlencode(data).encode()
request = urllib.request.Request(url=url, headers=headers, data=params)
#把自定義的opener當(dāng)初全局使用
# urllib.request.install_opener(opener)
# response = urllib.request.urlopen(request)
response = opener.open(request)
print(response.read().decode())
# 打印內(nèi)容
# with open("proxybaidu.html", 'w') as f:
# f.write(response.read().decode())
# print(response.read().decode())
Cookie
Cookie 是指某些網(wǎng)站服務(wù)器為了辨別用戶身份和進(jìn)行Session跟蹤体啰,而儲(chǔ)存在用戶瀏覽器上的文本文件攒巍,Cookie可以保持登錄信息到用戶下次與服務(wù)器的會(huì)話嗽仪。
Cookie原理 HTTP是無(wú)狀態(tài)的面向連接的協(xié)議, 為了保持連接狀態(tài), 引入了Cookie機(jī)制 Cookie是http消息頭中的一種屬性
from http import cookiejar
import urllib.request
import urllib.parse
# 先創(chuàng)建一個(gè)cookiejar對(duì)象,用來(lái)保存cookie
cookiejar = cookiejar.CookieJar()
# 創(chuàng)建一個(gè)能處理cookie的handler
cookie_handler = urllib.request.HTTPCookieProcessor(cookiejar)
# 生成一個(gè)opener對(duì)象
opener = urllib.request.build_opener(cookie_handler)
# 老登錄接口
url = 'http://www.renren.com/PLogin.do'
# 參數(shù)
data = {
'email': "496155678@qq.com",
'password': '123456789'
}
# 轉(zhuǎn)成二進(jìn)制數(shù)據(jù) 進(jìn)行傳輸
params = urllib.parse.urlencode(data).encode()
#構(gòu)建request
request = urllib.request.Request(url=url,data=params)
#發(fā)起請(qǐng)求
opener.open(request)
'''
只要登錄成功柒莉,自定義的opener就會(huì)把登錄后的cookie存到cookiejar當(dāng)中
如果繼續(xù)發(fā)起請(qǐng)求闻坚,就會(huì)把cookie自動(dòng)帶上
'''
#繼續(xù)發(fā)起請(qǐng)求
request1 = urllib.request.Request(url='http://www.renren.com/966325509/profile')
reponse = opener.open(request1)
with open('cookjarrenren.html','w')as f:
f.write(reponse.read().decode())