爬蟲(一)基礎知識(python)

1.1 定義

網絡爬蟲,也叫網絡蜘蛛(Web Spider),若是把互聯網比喻成一個蜘蛛網,Spider就是一隻在網上爬來爬去的蜘蛛。網絡爬蟲就是根據網頁的地址來尋找網頁的,也就是URL。舉一個簡單的例子,咱們在瀏覽器的地址欄中輸入的字符串就是URL,例如:https://www.baidu.com/html

URL就是贊成資源定位符(Uniform Resource Locator),它的通常格式以下(帶方括號[]的爲可選項):python

protocol :// hostname[:port] / path / [;parameters][?query]#fragment

URL的格式由三部分組成:es6

(1)protocol:第一部分就是協議,例如百度使用的就是https協議;json

(2)hostname[:port]:第二部分就是主機名(還有端口號爲可選參數),通常網站默認的端口號爲80,例如百度的主機名就是www.baidu.com,這個就是服務器的地址;api

(3)path:第三部分就是主機資源的具體地址,如目錄和文件名等。瀏覽器

網絡爬蟲就是根據這個URL來獲取網頁信息的。服務器

1.2 基本流程

在這裏插入圖片描述
爬蟲基本流程:markdown

  1. 首先選取一部分種子URL
  2. 將種子URL加入到待抓取任務隊列
  3. 從抓取任務隊列中取出URL,解析DNS,而且得到主機IP,並將對應網頁下載下來,存儲下來,而後把URL放到已經抓取的任務隊列中。
  4. 將網頁中的數據解析出來。
  5. 分析已經抓取URL任務隊列中的URL,其中包含的其餘URL,放到待抓取的任務隊列中。從而進去下一次循環。

2.1 urllib

urllib提供了一系列用於操做URL的功能。
Python3中將python2.7的urllib和urllib2兩個包合併成了一個urllib庫,其主要包括一下模塊:cookie

urllib.request 請求模塊網絡

urllib.error 異常處理模塊

urllib.parse url解析模塊

urllib.robotparser robots.txt解析模塊

GET

咱們使用urllib.request.urlopen()這個接口函數就能夠很輕鬆的打開一個網站,也就是發送一個GET請求到指定的頁面,而後返回HTTP的響應,urlopen參數以下:

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

urllib使用使用request.urlopen()打開和讀取URLs信息,返回的對象response如同一個文本對象,咱們能夠調用read(),進行讀取,一樣也可使用geturl()方法、info()方法、getcode()方法。

  1. geturl()返回的是一個url的字符串;
  2. info()返回的是一些meta標記的元信息,包括一些服務器的信息;
  3. getcode()返回的是HTTP的狀態碼,若是返回200表示請求成功。

例如,對csdn首頁https://www.csdn.net進行抓取,並返回響應:

from urllib import request

with request.urlopen('https://www.csdn.net/') as f:
    data = f.read()
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', data.decode('utf-8'))
    
# 能夠看到HTTP響應的頭和JSON數據:    
''' 
Status: 200 OK
Server: openresty
Date: Mon, 15 Jul 2019 07:31:40 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
Vary: Accept-Encoding
Set-Cookie: uuid_tt_dd=10_35252089750-1563175899898-449903; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net;
Set-Cookie: dc_session_id=10_1563175899898.455037; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net;
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000
Data: <!DOCTYPE html>...</script></div></html>
'''

若是咱們要想模擬瀏覽器發送GET請求,就須要使用Request對象,經過往Request對象添加http請求頭User-Agent,咱們就能夠把請求假裝成瀏覽器。例如,模擬手機端iphone6去請求csdn首頁:

from urllib import request

req = request.Request('https://www.csdn.net')
req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))
    
#返回適合iPhone的移動版網頁:
''' 
    <meta charset="utf-8">
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
'''

User Agent

有一些網站不喜歡被爬蟲程序訪問,因此會檢測鏈接對象,若是是爬蟲程序,也就是非人點擊訪問,它就會不讓你繼續訪問,因此爲了要讓程序能夠正常運行,須要隱藏本身的爬蟲程序的身份。此時,咱們就能夠經過設置User Agent的來達到隱藏身份的目的,User Agent的中文名爲用戶代理,簡稱UA。

User Agent存放於Headers中,服務器就是經過查看Headers中的User Agent來判斷是誰在訪問。在Python中,若是不設置User Agent,程序將使用默認的參數,那麼這個User Agent就會有Python的字樣,若是服務器檢查User Agent,那麼沒有設置User Agent的Python程序將沒法正常訪問網站。

Python容許咱們修改這個User Agent來模擬瀏覽器訪問,它的強大毋庸置疑。

經常使用的瀏覽器請求頭User-Agent彙總:

user_agent = [
    "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",
    "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
    "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
    "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
    "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11",
    "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
    "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
    "MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
    "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
    "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
    "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+",
    "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0",
    "Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)",
    "UCWEB7.0.2.37/28/999",
    "NOKIA5700/ UCWEB7.0.2.37/28/999",
    "Openwave/ UCWEB7.0.2.37/28/999",
    "Mozilla/4.0 (compatible; MSIE 6.0; ) Opera/UCWEB7.0.2.37/28/999",
    # iPhone 6:
	"Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25",
]

f.read().decode(‘utf-8’) 這就是瀏覽器接收到的信息,只不過咱們在使用瀏覽器的時候,瀏覽器已經將這些信息轉化成了界面信息供咱們瀏覽。固然這些代碼咱們也能夠從瀏覽器中點擊(F12或者開發者選項中)查看到。固然這個前提是咱們已經知道了這個網頁是使用utf-8編碼的,怎麼查看網頁的編碼方式呢?須要人爲操做,且很是簡單的方法是使用使用瀏覽器開發者選項,只須要找到head標籤開始位置的chareset,就知道網頁是採用何種編碼的了。以下:

在這裏插入圖片描述

POST

咱們可使用data參數,向服務器發送數據。根據HTTP規範,GET用於信息獲取,POST是向服務器提交數據的一種請求,
若是沒有設置urlopen()函數的data參數,HTTP請求採用GET方式,也就是咱們從服務器獲取信息,若是咱們設置data參數,HTTP請求採用POST方式,也就是咱們向服務器傳遞數據。
data參數有本身的格式,它是一個基於application/x-www.form-urlencoded的格式,具體格式咱們不用瞭解, 由於咱們可使用urllib.parse.urlencode()函數將字符串自動轉換成上面所說的格式。

舉例子說明:向有道翻譯發送data,獲得翻譯結果。
具體詳情見:https://blog.csdn.net/weixin_42251851/article/details/80489403

urllib提供的功能就是利用程序去執行各類HTTP請求。若是要模擬瀏覽器完成特定功能,須要把請求假裝成瀏覽器。假裝的方法是先監控瀏覽器發出的請求,再根據瀏覽器的請求頭來假裝,User-Agent頭就是用來標識瀏覽器的。

2.2 requests

Python內置的urllib模塊,用於訪問網絡資源。可是,它用起來比較麻煩,並且,缺乏不少實用的高級功能。

更好的方案是使用requests。它是一個Python第三方庫,處理URL資源特別方便。

使用requests要經過GET訪問一個頁面,只須要幾行代碼:

import requests
r = requests.get('https://www.csdn.net/') 
print(r.status_code)
print(r.text)

對於帶參數的URL,傳入一個dict做爲params參數:

r = requests.get('https://www.douban.com/search', params={'q': 'python', 'cat': '1001'})
 print(r.url) # 實際請求的URL

'''
'https://www.douban.com/search?q=python&cat=1001'
'''

requests自動檢測編碼,可使用encoding屬性查看:

print(r.encoding)
'''
'utf-8'
'''

不管響應是文本仍是二進制內容,咱們均可以用content屬性得到bytes對象:

print(r.content)
'''
b'<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n...'
'''

requests的方便之處還在於,對於特定類型的響應,例如JSON,能夠直接獲取:

r = requests.get('https://query.yahooapis.com/v1/public/yql?
r.json()

須要傳入HTTP Header時,咱們傳入一個dict做爲headers參數:

r = requests.get('https://www.douban.com/', headers={'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'})

 

要發送POST請求,只須要把get()方法變成post(),而後傳入data參數做爲POST請求的數據:

r = requests.post('https://accounts.douban.com/login', data={'form_email': 'abc@example.com', 'form_password': '123456'})

 

requests默認使用application/x-www-form-urlencoded對POST數據編碼。若是要傳遞JSON數據,能夠直接傳入json參數:

params = {'key': 'value'}
r = requests.post(url, json=params) # 內部自動序列化爲JSON

相似的,上傳文件須要更復雜的編碼格式,可是requests把它簡化成files參數:

upload_files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=upload_files)

在讀取文件時,注意務必使用’rb’即二進制模式讀取,這樣獲取的bytes長度纔是文件的長度。

把post()方法替換爲put(),delete()等,就能夠以PUT或DELETE方式請求資源。

除了能輕鬆獲取響應內容外,requests對獲取HTTP響應的其餘信息也很是簡單。例如,獲取響應頭:

r.headers

 

requests對Cookie作了特殊處理,使得咱們沒必要解析Cookie就能夠輕鬆獲取指定的Cookie:

print(r.cookies['ts'])

'''
'example_cookie_12345'
'''

要在請求中傳入Cookie,只需準備一個dict傳入cookies參數:

cs = {'token': '12345', 'status': 'working'}
 r = requests.get(url, cookies=cs)

最後,要指定超時,傳入以秒爲單位的timeout參數:

r = requests.get(url, timeout=2.5) # 2.5秒後超時

 

更多詳細介紹,可參考:http://www.javashuo.com/article/p-awbuoqmy-nt.html
https://www.liaoxuefeng.com/wiki/1016959663602400/1183249464292448

相關文章
相關標籤/搜索