爬蟲學習筆記【1】 使用 urllib 獲取 www 資源
1. 掌握普通網頁的獲取方法
檢視 urllib.request 的基本資訊
urllib.request
中最常用的方法是 urlopen()
,它也是我們使用 urllib
獲取普通網頁的基本方法。 在應用之前,我們先看一下 urllib
的原始碼,這是從事IT軟體類技術工作要養成的職業習慣。 由於 urllib
是 python3
內建庫,所以無需安裝。 原始碼的路徑可以在 import urllib
或 import.request
後,使用 file
屬性檢視。
import urllib.request #可以使用語句檢視摘要資訊 print(urllib.request.__all__) #可以使用語句檢視urllib的本地位置 print(urllib.request.__file__)
urllib.request.urlopen() 方法的應用
從頭部註釋中可以瞭解 urlopen
方法需要傳入一個字串引數:頁面的URL
,然後它會開啟這個URL,返回類檔案物件的響應物件。
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,*, cafile=None, capath=None, cadefault=False, context=None)
檢視上面 urlopen
方法原型,瞭解它的功能和呼叫方法。可以看到, url
是必須給定的引數,其他引數可以預設。下面我們嘗試使用 urlopen
我們使用了 with...as...
語句呼叫,這樣會更有利於在不使用時正常關閉連線。返回的結果是 HTTPResponse
物件。呼叫這個物件的 read()
方法,可以訪問具體的檔案內容。
"""簡單網頁獲取""" import urllib.request url = 'http://www.smartcrane.club' #使用urlopen開啟網頁 #使用 with ... as ... 語句呼叫,有利於在不適用的時候正常關閉連線 with urllib.request.urlopen(url) as resp: print(resp.read().decode('utf-8'))
urllib.request.urlretrieve() 方法的應用
urllib.request.urlretrieve()
方法能夠以另一種形式獲取頁面內容,它會將頁面內容存為臨時檔案並獲取 response
頭。
可以檢視 urlretrieve
方法的原型:
def urlretrieve(url, filename=None, reporthook=None, data=None)
"""urlretrieve()方法試用"""
import urllib.request
tempfile,header = urllib.request.urlretrieve(url)
print(header)
print('--'*10)
print(tempfile)
理解 HTTPResponse 物件
HTTPResponse
物件是一種類檔案物件,除了可以檔案的 read()
方法讀取它的內容外,還有別的屬性和方法。
例如: r.code
與 r.status
屬性存放本次請求的響應碼; r.headers
屬性存放響應頭; r.url
屬性存放了發出響應的伺服器URL;還可以嘗試 info()
和 geturl()
方法。
(使用 response
的 geturl()
和 info
方法來驗證請求與響應是否如我們希望的一樣。有時會出現請求發往的伺服器與應答伺服器不是同一臺主機的情況。)
"""理解 HTTPResponse 物件"""
import urllib.request
url = 'http://www.smartcrane.club'
with urllib.request.urlopen(url) as resp:
print(resp)
print(resp.code)
print(resp.status)
print(resp.headers)
print(resp.url)
print(resp.info())
print(resp.geturl())
2. 掌握使爬蟲更像瀏覽器的方法
預設情況下,urllib發出的請求頭大致如下所示:
GET / HTTP/1.1
Accept-Encoding: identity
Host: 10.10.10.135
User-Agent: Python-urllib/3.6
Connection: close
大多數網站的伺服器端會進行內容審查,檢查客戶端型別,一方面是為了滿足多樣化的需求;另一方面也可以 限制一些網路爬蟲程式的訪問。
上面內容中的 User-Agent
就是一個內容審查重點,一般的瀏覽器發出的請求頭如下所示:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Cookie: _ga=GA1.2.1750953090.1536588381; _gid=GA1.2.14861119.1539324601; _gat=1
Host: www.smartcrane.club
If-Modified-Since: Tue, 09 Oct 2018 06:29:24 GMT
If-None-Match: W/"5bbc4ac4-82e1"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
伺服器發現不是正常瀏覽器可以拒絕提供服務,例如訪問 www.z.cn 時,使用下面程式碼會報出 HTTP Error 503: Service Unavailable:()
with urllib.request.urlopen(url) as response:
print(response.status)
這時我們可以定製請求物件 HTTPRequest
,是指更像是瀏覽器發出的。
"""定製 request 物件,使爬蟲更像瀏覽器"""
import urllib.request
url = 'http://www.smartcrane.club'
header = {
'Accept': 'text/html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
request = urllib.request.Request(url = url, headers = header)
with urllib.request.urlopen(request) as resp:
print(resp.status)
3. 掌握向伺服器傳遞引數的方法
許多 HTTP
方法都可以用來向伺服器提供資料,最常見的 GET
和 POST
方法都可以,但方式不同。
使用 GET 方法向伺服器提供資料
"""向伺服器提交引數"""
import urllib.parse
import urllib.request
#1 利用 Get 方法通過 URL 引數提交資訊
url = 'http://www.baidu.com/s?'
wd = {'wd':'北航'}
wdcoded = urllib.parse.urlencode({'wd':'北航'})
url1 = url + wdcoded
header = {
'Accept': 'text/html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
request = urllib.request.Request(url = url, headers = header)
with urllib.request.urlopen(request) as resp:
print(resp.status)
print(resp.headers)
print(resp.read().decode('utf-8'))
使用 POST 方法向伺服器提供資料
"""
利用 POST 方法,向 http://httpbin.org 提交
事先應在該網站進行設定,啟動試用連結
"""
import urllib.request
import urllib.parse
url = 'http://www.httpbin.org/post'
payload = {'key1':'value1','key2':'value'}
header = {
'Accept': 'text/html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
}
request = urllib.request.Request(url=url,data=urllib.parse.urlencode(payload).encode('utf-8'),headers=header)
with urllib.request.urlopen(request) as resp:
print(resp.read().decode('utf-8'))
4. 掌握設定超時訪問限制和處理異常的方法
urllib.error
處理異常,兩個常用異常類:urllib.error.URLError
和 HTTPError
設定 Time-Out 超時訪問限制
"""設定 Time-Out"""
import urllib.request
import socket
# tineout in seconds
timeout = 3
socket.setdefaulttimeout(timeout)
# this call to urllib.request.urloopen now uses the default timeout
# we have set in the socket module
req = urllib.request.Request("http://www.python.org/")
a = urllib.request.urlopen(req).read()
print(a)
使用 urllib.error 處理異常
URLError
繼承自 OSError
,是 urllib
的異常的基礎類。HTTPError
是驗證 HTTP Response
例項的一個異常類。
HTTP protocol errors
是有效的 response
,有 狀態碼
、 header
、 body
。
"""使用urlllib.error處理異常"""
import urllib.request
import urllib.error
import urllib.parse
import logging
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='C:\\Users\\Wen Xuhonghe\\Documents\\Crawler\\CrawlerLesson1_crawler.log',
level=logging.DEBUG)
try:
url = 'http://www.baidu11.com' # A wrong website url
headers = {
'Accept': 'text/html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
}
request = urllib.request.Request(url,headers=headers)
with urllib.request.urlopen(request) as response:
print(response.status)
print(response.read().decode('utf-8'))
except urllib.error.HTTPError as e:
import http.server
#print(http.server.BaseHTTPRequestHandler.response[e.code])
logging.error('HTTPError code: %s and Messages: %s' %(str(e.code),http.server.BaseHTTPRequestHandler.response[e.code]))
logging.info('HTTPError headers: ' + str(e.headers))
logging.info(e.read().decode('utf-8'))
print('Error : urllib.error.HTTPError')
except urllib.error.URLError as e:
logging.error(e.reason)
print('Error : urllib.error.URLError')
5. 例項:從百度貼吧下載多頁話題內容
- loadPage(url) 用於獲取網頁
- writePage(html,filename) 用於將已獲得的網頁儲存為本地檔案
- tiebaCrawler(url,beginpPage,endPage,keyword)用於排程,提供需要抓取的頁面URLs
- main:程式主控模組,完成基本命令列互動介面
import urllib.request
import urllib.error
import urllib.parse
import logging
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='C:\\Users\\Wen Xuhonghe\\Documents\\Crawler\\CrawlerLesson1_crawler.log',
level=logging.DEBUG)
def loadPage(url):
try:
headers = {
'Accept': 'text/html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
}
request = urllib.request.Request(url,headers=headers)
with urllib.request.urlopen(request) as response:
print(response.status)
#print(response.read().decode('utf-8'))
return response.read()
except urllib.error.HTTPError as e:
import http.server
#print(http.server.BaseHTTPRequestHandler.response[e.code])
logging.error('HTTPError code: %s and Messages: %s' %(str(e.code),http.server.BaseHTTPRequestHandler.response[e.code]))
logging.info('HTTPError headers: ' + str(e.headers))
logging.info(e.read().decode('utf-8'))
print('Error : urllib.error.HTTPError')
except urllib.error.URLError as e:
logging.error(e.reason)
print('Error : urllib.error.URLError')
def WritePage(html, filename):
fp=open(filename,'w+b')
fp.write(html)
fp.close()
if __name__ == "__main__":
for i in range(3):
url = 'http://tieba.baidu.com/p/5872199831?pn=' + str(i+1)
response = loadPage(url)
filename = 'C:\\Users\\Wen Xuhonghe\\Documents\\Crawler\\CrawlerLesson1_Tieba' + str(i+1) + '.html'
WritePage(response,filename)