Python 爬蟲、抓包

因為想所以努力發表於2020-05-04

什麼是爬蟲?

爬蟲就是模擬客戶端(瀏覽器、電腦app、手機app)傳送網路請求,獲取相應,按照規則提取資料的程式。
模擬客戶端傳送網路請求:照著瀏覽器一模一樣的請求,獲取和瀏覽器一模一樣的資料

爬蟲的應用:

爬蟲的資料
可以呈現在網頁上、app上 例如:新聞、視訊等。
也可以獲取資料,進行資料的分析找出潛藏在資料中的規律 例如:百度指數

開發環境:

python3,pycharm、谷歌或者火狐瀏覽器。其他的ide也可以

瀏覽器請求分析

每當我們在百度的搜尋框輸入內容並點選‘’百度一下‘’的時候,瀏覽器會傳送很多的網路請求,我們可以按住鍵盤上的F12鍵來調出瀏覽器的控制檯,在控制檯上點選網路選項卡可以看到所有的請求
在這裡插入圖片描述每個請求都會有一個請求頭(Headers)

URL地址的分析:
在這裡插入圖片描述

https協議 : // www.baidu.com域名 /s路徑 之後是引數: ?wd=python&rsv_spt=1&rsv_iqid=0xb90688580000985e&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=monline_3_dg&rsv_enter=0&rsv_dl=tb&oq=python&rsv_btype=t&rsv_t=9484QpHB9LMCHKDPPF%2BY96BVmt1lfZjE%2Bk9CGPHaEo0FMWrJWfFAwqV%2Fo8OW38Xrg2M7&rsv_pq=e6e817bb008a53ce

  • 協議:https 或者 http
  • 網站的域名:www.baidu.com
  • 資源路徑:/s 等 像檔案路徑一樣的東西
  • 引數:以問號開頭,a=b、c=d、&符號連線,出現百分號+數字的是UrlEncode編碼,我們可以搜尋解碼器來解碼。

瀏覽器請求的過程:

  • 點選搜尋之後,瀏覽器會請求url地址,我們可以看 控制檯->網路的第一個請求地址,然後找響應(這個響應就時當前伺服器根據你的url返回的內容,也可以通過在頁面上右鍵點選檢視網頁原始碼,檢視當前url所對應的響應在這裡插入圖片描述
    這兩處的內容時相同的注意:也會有不同的時候,例如:有些網站更新內容比較快,像貼吧等網站,但網站的框架是一樣的,只是填充的內容不同而已):
    在這裡插入圖片描述響應選項卡中會有一些字串,瀏覽器就會去解析這些字串,然後渲染介面,渲染過程中會發現有圖片的url地址、js的url地址、css的url地址等,那麼瀏覽器會再次傳送網路請求來請求這些檔案,如此變導致了網路選項卡中有很多請求。

爬蟲的請求:

  • 請求時只會請求當前url地址的響應,並不會解析當前響應並去繼續請求css、js等檔案。就算你把css、js等檔案全部請求下來,爬蟲也不會將這些檔案渲染在一起組成瀏覽器這樣的介面。由此可以看到,爬蟲可以做到瀏覽器做到的一些事情,像投票、買票、購物、下載等

Http 與 Https

  • 在控制檯 -> 網路 選中請求後,第一個標籤頁Headers中 下面General:Request Url 或者在這裡插入圖片描述中經常會看到http 或者 https

Http:

  • 超文字傳輸協議
  • 明文形式傳輸,例如:賬號、密碼
  • 效率高、不安全l

Https:

  • http + ssl(安全套接字層)
  • 加密形式傳輸,傳輸之前先加密,之後解密獲取內容
  • 效率低、安全

其他引數分析:

請求頭

在訊息頭中包含的請求頭有如下內容
在這裡插入圖片描述

  • Connection:Keep-alive 通知伺服器,客戶端支援長連結,如果伺服器也支援長連結,那麼就會在建立連線之後再請求相同網站內容時會複用第一次的連結,縮短請求時間。

  • Cache-Control:快取控制,max-age=0,客戶端對服務端不做任何快取

  • User-Agent:使用者代理,可以理解成瀏覽器的身份標識,可以通過這個表示讓伺服器知曉我們使用的是什麼裝置在請求資料。
    火狐瀏覽器:
    電腦端:
    Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
    手機安卓端:
    Mozilla/5.0 (Android; Mobile; rv:18.0) Gecko/18.0 Firefox/18.0
    IE瀏覽器 :
    Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
    等等。。。,這是非常重要的引數,伺服器可以根據這個來區分爬蟲。同樣的爬蟲也會使用這個引數來偽裝自己。

  • Upgrade-Insecure-Requests:客戶端通知服務端將不安全的請求轉換為安全的請求,將http變為https等

  • Accept:客戶端可以接收型別的資料

  • Accept-Encoding:客戶端可以接收什麼編碼方式的資料如gzip 一種壓縮方式等

  • Accept-Language:客戶端可以接收什麼語言的資料

  • Cookie:客戶端儲存的使用者資訊,通過Cookie可以獲取到登入之後才能獲取的資訊。例如:賬號、密碼、狀態資訊,此引數可以區分爬蟲與程式,此引數也很重要,每次請求都要攜帶。

請求體

可以從網路標籤頁中看請求是get還是post

  • get請求是沒有請求體的,引數放在url中
  • post請求是有請求體,請求體中是引數,常用於登入、註冊、傳輸大文字的時候

響應

響應頭

在這裡插入圖片描述Set-Cookie:伺服器通過這個欄位來設定客戶端的Cookie
當然還可以通過js來設定客戶端本地的Cookie
在這裡插入圖片描述這裡的cookie可以從請求頭中檢視到,比較關鍵

響應體

在這裡插入圖片描述爬蟲偽裝是呢,就是模擬請求頭中的關鍵內容如:UserAgent、Cookie等即可

request 模組學習

安裝

pip install requests

使用

傳送請求的方式:

get請求
response = requesrs.get(url)

傳送get請求並使用response來接收響應

import requests
url = "http://www.baidu.com"
response = requests.get(url)
print(response)

在這裡插入圖片描述尖括號往往代表著一個物件,Response是個物件 200是個請求成功的狀態碼

post請求
response = requests.post(url,data={請求體的字典})

傳送一個post請求
這裡利用手機版本的 百度翻譯舉例子
在這裡插入圖片描述
在這裡插入圖片描述

import requests
url = "https://fanyi.baidu.com/basetrans" # url地址在請求頭中可以看見
query_string = {"query":"人生",
        "from":"zh",
        "to":"en"} # 引數
response = requests.post(url,data=query_string);
print(response)

在這裡插入圖片描述結果仍然是個物件,之後會解釋如何變成字串
在這裡插入圖片描述

解析物件

方式一:
response.text #該方式會出現亂碼

獲取響應中的字串

以get請求獲取字串為例子(post請求相同):
在這裡插入圖片描述解碼格式需要變化:一般網頁都是utf-8格式,在 response.text 之前加上一個response.encoding="utf-8" #指定解碼格式即可
在這裡插入圖片描述

方式二:
response.content # 返回的是一個byte型別,也需要解碼
response.content.decode() #對byte型別進行解碼,更方便

在這裡插入圖片描述在這裡插入圖片描述

方式三:

在使用上面兩種都不可以後,要替換成下面的程式碼

response.content.decode("gbk") 
response.text #碰運氣
使用post請求被服務端判斷為爬蟲:在這裡插入圖片描述
使用response檢視當前響應的資訊
response.request.url # 檢視當前響應的網址
response.request.headers # 檢視請求頭
response.headers # 檢視響應頭

新增headers

這些請求頭都是一個一個引數嘗試出來的,需要就向裡面新增,包括引數也是,這些內容都可以從瀏覽器控制檯頁面的網路標籤頁中的請求中找到。若不加headers,伺服器會判斷你是一個爬蟲,並返回你一個假資料

headers = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1","Referer":"https://fanyi.baidu.com/?aldtype=16047"}
import requests
url = "https://fanyi.baidu.com/basetrans" # url地址在請求頭中可以看見
query_string = {"query":"人生",
        "from":"zh",
        "to":"en",
        "token":"6b8e1547cd61317e9e54c2da738b6740",
        "sign":"548627.834594"} # 引數
headers_string = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
                  "Cookie":"BAIDUID=3652EB1E13515625B5134EB764EDE4C3:FG=1; BIDUPSID=3652EB1E13515625D2A00EC620247A3A; PSTM=1584412752; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1588206030,1588481363,1588546956,1588566527; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDUSS=s2MWVIZ0xteVRtQUdRRUo0WFgtQkc3VjZmSmlrcjNKU2Q4dEt0SFl0T1BCdEplRVFBQUFBJCQAAAAAAAAAAAEAAADeVvzoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI95ql6PeapeS0; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; yjs_js_security_passport=7e8d62bafc4c8187893cfbd6840f2b54c2ace19e_1588569021_js; H_PS_PSSID=1463_31326_21102; delPer=0; PSINO=1; BDRCVFR[Fc9oatPmwxn]=aeXf-1x8UdYcs; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1588569155; Hm_lvt_afd111fa62852d1f37001d1f980b6800=1588566596; Hm_lpvt_afd111fa62852d1f37001d1f980b6800=1588569155"}
response = requests.post(url,data=query_string,headers=headers_string);
print(response.content.decode())

在這裡插入圖片描述

超時引數

網路有延遲時,規定一段時間內返回資料否則報錯

response = requests.get(url.headers=headers,timeout=3)

3s內必須返回響應否則會報錯

retrying模組的使用
pip install retrying
from retrying import retry
#執行的函式程式碼
@retry(stop_max_attempt_number=3) # 讓被裝飾的函式反覆執行3次,三次全部報錯才報錯,中間的報錯正常
def _parse_url(url,headers_string):
    """關於請求url地址的方法"""
    response = requests.get(url,headers=headers_string,timeout=5)
    return response.content.decode()
    
def parse_url(url,headers_string):
	"""這裡用來返回錯誤資訊"""
    try:
        html_str = _parse_url(url,headers_string)
    except:
        html_str = None
    return html_str

正例子:

import requests
from retrying import retry

@retry(stop_max_attempt_number=3) # 讓被裝飾的函式反覆執行3次,三次全部報錯才報錯,中間的報錯正常
def _parse_url(url,headers_string):
    """關於請求url地址的方法"""
    print("*"*100)
    response = requests.get(url,headers=headers_string,timeout=5)
    return response.content.decode()

def parse_url(url,headers_string):
    try:
        html_str = _parse_url(url,headers_string)
    except:
        html_str = None
    return html_str

url = "https://www.baidu.com" # url地址在請求頭中可以看見
headers_string = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
                  "Cookie":"BAIDUID=3652EB1E13515625B5134EB764EDE4C3:FG=1; BIDUPSID=3652EB1E13515625D2A00EC620247A3A; PSTM=1584412752; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1588206030,1588481363,1588546956,1588566527; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDUSS=s2MWVIZ0xteVRtQUdRRUo0WFgtQkc3VjZmSmlrcjNKU2Q4dEt0SFl0T1BCdEplRVFBQUFBJCQAAAAAAAAAAAEAAADeVvzoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI95ql6PeapeS0; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; yjs_js_security_passport=7e8d62bafc4c8187893cfbd6840f2b54c2ace19e_1588569021_js; H_PS_PSSID=1463_31326_21102; delPer=0; PSINO=1; BDRCVFR[Fc9oatPmwxn]=aeXf-1x8UdYcs; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1588569155; Hm_lvt_afd111fa62852d1f37001d1f980b6800=1588566596; Hm_lpvt_afd111fa62852d1f37001d1f980b6800=1588569155"}
print(parse_url(url,headers_string)[:20])

在這裡插入圖片描述
反例子:

將上面程式碼的url改成:www.baidu.com 即可

在這裡插入圖片描述

處理Cookie相關的請求

1.直接在headers中攜帶Cookie引數,詳情請往上翻,檢視
新增Headers模組,post請求百度翻譯 的程式碼
2.直接在requests.get();或者requests.post();引數中傳入Cookie的引數

import requests

url = "https://fanyi.baidu.com/basetrans" # url地址在請求頭中可以看見
query_string = {"query":"人生",
        "from":"zh",
        "to":"en",
        "token":"6b8e1547cd61317e9e54c2da738b6740",
        "sign":"548627.834594"} # 引數
headers_string = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"}

cookie = "BAIDUID=3652EB1E13515625B5134EB764EDE4C3:FG=1; BIDUPSID=3652EB1E13515625D2A00EC620247A3A; PSTM=1584412752; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1588206030,1588481363,1588546956,1588566527; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDUSS=s2MWVIZ0xteVRtQUdRRUo0WFgtQkc3VjZmSmlrcjNKU2Q4dEt0SFl0T1BCdEplRVFBQUFBJCQAAAAAAAAAAAEAAADeVvzoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI95ql6PeapeS0; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; yjs_js_security_passport=7e8d62bafc4c8187893cfbd6840f2b54c2ace19e_1588569021_js; H_PS_PSSID=1463_31326_21102; delPer=0; PSINO=1; BDRCVFR[Fc9oatPmwxn]=aeXf-1x8UdYcs; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1588569155; Hm_lvt_afd111fa62852d1f37001d1f980b6800=1588566596; Hm_lpvt_afd111fa62852d1f37001d1f980b6800=1588569155";
cookie_dit = {i.split("=")[0] : i.split("=")[1] for i in cookie.split("; ")}
print(cookie_dit)
response = requests.post(url,data=query_string,headers=headers_string,cookies=cookie_dit);
print(response.content.decode())

在這裡插入圖片描述
但是如果cookie中有干擾項則沒有第一種來的方便
如:

BAIDUID=3652EB1E13515625B5134EB764EDE4C3:FG=1
增加了分析的時長

3.seesion傳送post請求獲取cookie,帶上cookie再請求
cookie的持久化保持
以人人網為例子:

1.seesion = requests.session() # session方法具有和requests一樣的方法
2.session.post(url,data,headers); # 假設成功 伺服器的cookie會儲存在seesion中
3.seesion.get(url) #會帶上之前儲存在seesion的cookie
import requests

url = "http://www.renren.com/PLogin.do"
query_string = {"email":"*******","password":"*******"}
headers_string = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"}
seesion = requests.session()
seesion.post(url,data=query_string,headers=headers_string)

url = "http://www.renren.com/974362318/newsfeed/photo"
response = seesion.get(url,headers=headers_string)
print(response.content.decode())

在這裡插入圖片描述
這些登入的介面可以在 控制檯的檢視器中找到,如果找不到可以在網路標籤頁中通過抓包一個一個分析得到,在登入時,頁面會重新整理,如果想保持記錄可以將保持記錄打勾
在這裡插入圖片描述也可以用第三方抓包工具如:Fidder等

資料分析

json

  • 資料交換格式,型別像python的列表或者字典但其實是個字串
  • json的解析:json.loads 將json字串轉換為python型別
import requests
import json
url = "https://fanyi.baidu.com/basetrans" # url地址在請求頭中可以看見
query_string = {"query":"人生",
        "from":"zh",
        "to":"en",
        "token":"6b8e1547cd61317e9e54c2da738b6740",
        "sign":"548627.834594"} # 引數
headers_string = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
                  "Cookie":"BAIDUID=3652EB1E13515625B5134EB764EDE4C3:FG=1; BIDUPSID=3652EB1E13515625D2A00EC620247A3A; PSTM=1584412752; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1588206030,1588481363,1588546956,1588566527; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDUSS=s2MWVIZ0xteVRtQUdRRUo0WFgtQkc3VjZmSmlrcjNKU2Q4dEt0SFl0T1BCdEplRVFBQUFBJCQAAAAAAAAAAAEAAADeVvzoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI95ql6PeapeS0; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; yjs_js_security_passport=7e8d62bafc4c8187893cfbd6840f2b54c2ace19e_1588569021_js; H_PS_PSSID=1463_31326_21102; delPer=0; PSINO=1; BDRCVFR[Fc9oatPmwxn]=aeXf-1x8UdYcs; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1588569155; Hm_lvt_afd111fa62852d1f37001d1f980b6800=1588566596; Hm_lpvt_afd111fa62852d1f37001d1f980b6800=1588569155"}
response = requests.post(url,data=query_string,headers=headers_string);
print(json.loads(response.content.decode()))
print(type(json.loads(response.content.decode())))

在這裡插入圖片描述
之後操作字典來獲取對應的值

print("翻譯:"+json.loads(response.content.decode())["trans"][0]["dst"])

在這裡插入圖片描述

  • 將python的字典轉化為json用json.dumps();
json.dumps(傳入字典,ensure_ascii=False 顯示中文,indent=2 換行的效果)

xpath

  • 一門用來從html中提取資料的語言

  • xpath helper外掛:幫助從elements中定位資料,但爬蟲是抓不到elements中的資料的,因為elements中的資料是根據js渲染的。如果url的響應的資料與elements一樣時就可以用。

  • 常用語法:

  • 1.選擇節點 / 標籤
    /html/head/meta 能夠選中html下的head下的所有的meta標籤

  • 2.選擇當前頁面下的任何一個節點 //
    //li選擇整個頁面下的所有li標籤
    /html/head//link選中head下的所有的li標籤

  • 3選擇指定的標籤
    //div[@class="xxxx"]/ul/li 對標籤進行限定

  • 4.取標籤中的值
    /a/@herf取a標籤中的herf值

  • 5.獲取標籤中的文字
    /a/text()取a標籤中的text值
    /a//text()取a標籤中的所有text值

使用lxml

  • 安裝lxml
pip install lxml
  • 使用
from lxml import etree
element = etree.HTML("html字
符串")
element.xpath("") //引號中填入對應的xpath表示式
  • element.xpath() 返回的使一個element物件,我們可以用list來接收

urlEncode的解碼與編碼

  • 在寫爬蟲的時候,經常會看到連結中有類似於這樣的字串:

%e6%88%91%e7%9a%84%e4%b8%96%e7%95%8c

以上的urlencode的意思是:我的世界

  • 在python3中我們可以使用urllib中的parse模組
from urllib import parse

編碼:

print(parse.quote("我的世界"))

在這裡插入圖片描述
解碼:

print(parse.unquote("%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C"))

在這裡插入圖片描述

by黑馬程式設計師有感

相關文章