python 爬蟲(二)requests模塊的介紹 + 基於requests模塊的get請求和post請求 + 相關爬取案例(百度貼吧 + 百度產品 + 有道翻譯 + 百度翻譯)

一、requests模塊


注意:
python模塊的名字非常重要,一定要記住響應功能的導包語句。


1. requests模塊的定義


requests模塊是python中原生的基於網絡請求的模塊,其主要作用是用來模擬瀏覽器發起請求。功能強大,用法簡潔高效。在爬蟲領域中佔據着半壁江山的地位。


2. 使用requests模塊的原因


  • 因爲在使用urllib模塊的時候,會有諸多不便之處,總結如下:

    • 手動處理url編碼
    • 手動處理post請求參數
    • 處理cookie和代理操作繁瑣
  • 而使用requests模塊

    • 自動處理url編碼
    • 自動處理post請求參數
    • 簡化cookie和代理操作

總結:

requests是基於python內置的urllib3來編寫的,它比urllib更加方便,特別是在添加headers,post請求,以及cookies的設置上,處理代理請求,用幾句話就可以實現,而urllib比較繁瑣,requests比urllib方便多了,requests是一個簡單易用的http請求庫。


3. 如何使用requests模塊


  • 安裝(如果使用的是Anaconda編譯器,便不用執行這一步):

    pip install requests
    
  • 使用流程
    ① 指定url
    ② 基於requests模塊發起請求
    ③ 獲取響應對象中的數據值
    ④ 持久化存儲


二、基於requests模塊的請求


1. requests模塊get請求


① 完成請求的步驟


  1. 導包

    import requests
    
  2. 確定請求的url

    base_url = ''
    
  3. 發送請求,獲取響應

    	response = requests.get(
    		url = base_url,#請求的url
    		headers={},請求頭
    		params = {},請求參數字典
    	)
    

② response對象包含的內容


(1)狀態碼:

response.status_code

(2)響應頭:

response.headers['Cookie']

(3)響應正文:

1.獲取字符串類型的響應正文
	response.text
2.獲取bytes類型的響應正文
	response.content
3.響應正文字符串編碼
	response.encoding

(4)響應內容的亂碼問題:

當我們用response.text獲取字符串的響應正文的時候,有時候會出現亂碼:

原因是response.encoding這個字段默認指定編碼有誤。

  • 解決辦法
    第一種:

    手動指定
    response.encoding = ‘utf-8’
    

    第二種:

    	response.content.decode('utf-8')
    

③ get請求的項目類別三種情況


1. 沒有請求參數的

比如百度和百度產品這兩個項目,我們只需要添加請求頭,封裝user-agent這個請求頭就可以了。

案例:
百度

##########爬取固定url無參數#################

## 1.導包
import requests
## 2. 確定url
base_url = 'http://www.baidu.com/'

## 封裝請求頭字典
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36'
}

## 3. 發送請求,獲取響應

# response = requests.get(base_url,headers=headers)
with requests.get(url=base_url,headers=headers) as response:
    if response.status_code == 200 :
        with open('baidu.html', 'w', encoding='utf-8') as fp:
            fp.write(response.content.decode('utf-8'))
    else:
        print(response.status_code)


## 查看頁面內容
# print(response.text)

## fp = open('baidu.html','w',encoding='utf-8')
# with open('baidu.html','w',encoding='utf-8') as fp:
#     fp.write(response.content.decode('utf-8'))

百度產品

## 1.導包
import requests
## 2. 確定url
base_url = 'http://www.baidu.com/more/'

## 3. 發送請求,獲取響應

response = requests.get(base_url)

## 查看頁面內容
# print(response.text)
# print(response.encoding)

## 解決亂碼
response.encoding='utf-8'
# print(response.text)

print(response.status_code)
print(response.headers)
print(type(response.text))
print(type(response.content))



# with open('index.html','w',encoding='utf-8') as fp:
    ## 如果寫了上面一種解決亂碼
    # fp.write(response.text)
    ## 如果上面沒解決亂碼
    # fp.write(response.content.decode('utf-8'))

2. 帶請求參數的

比如新浪新聞這個項目
基礎url就是問號以前包括問號的內容。
設置請求參數字典:
params = {
字典的內容就是chrome裏面query string params裏面的內容
}

案例:新浪新聞

###########爬取帶參數的get請求網頁?name="zhanbgsan"###########
import requests
## 帶參數的get請求,基礎url就是?之前包括問號的內容
base_url = 'http://search.sina.com.cn/?'

## 先要設置hearders字典和params字典,再發請求
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36'
}

key = '王者'
params = {
 'q': key,
'c': 'news',
'from': 'channel',
'ie': 'utf-8',
}

response = requests.get(base_url,headers=headers,params=params)

with open('sina.html','w',encoding='gbk') as fp:
    fp.write(response.content.decode('gbk'))


3. 分頁—百度貼吧

方法:
	1.先找出分頁的規律。一般是通過params參數中的其中一個參數來控制的。
	2.找到這個參數每一頁的規律。
	3.用for循環來請求每一頁的內容。

案例:百度貼吧

import requests,os

base_url = 'http://tieba.baidu.com/f?'

## headers和params字典
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36'
}
kw = '雙十一'
## 一個路徑,這個路徑所對應的內容就是最後面的那個名字
dirname = './tieba/'+kw
parent_dir = os.path.dirname(dirname)
if not os.path.exists(parent_dir):
    os.mkdir(parent_dir)
if not os.path.exists(dirname):
    os.mkdir(dirname)

for i in range(10):
    params = {
        'ie': 'utf - 8',
        'kw':kw,
        'pn': str(i*50)
    }
    response = requests.get(base_url,headers=headers,params=params)
    with open(dirname+'/雙十一第%s頁.html' %(i+1),'w',encoding='utf-8') as fp:
        fp.write(response.text)

封裝成面向對象

import requests


class Fanyi_baidu():
    def __init__(self,kw):
        self.base_url = 'https://fanyi.baidu.com/sug'
        self.data = {
             'kw': kw
            }
        self.headers = {
    ## 百度沒有反爬措施,所以不寫也行
    'content-length': str(len(self.data)),
    'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'origin': 'https://fanyi.baidu.com',
    'referer': 'https://fanyi.baidu.com/',
    'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
}


    def result(self):
        response = requests.post(self.base_url,headers=self.headers,data=self.data)
        json_data = response.json()
        result = ''
        for data in json_data["data"]:
            result += data['v'] + '\n'
        return result

kw = input("請輸入你要查詢的英文單詞:")
a = Fanyi_baidu(kw)
print(a.result())


④ 查看網頁使用的是get請求還是post請求的方法


在這裏插入圖片描述
get請求的url
在這裏插入圖片描述


⑤ 請求載體身份標識的僞裝


  • User-Agent:請求載體身份標識,通過瀏覽器發起的請求,請求載體爲瀏覽器,則該請求的User-Agent爲瀏覽器的身份標識,使用爬蟲程序發起的請求,則該請求的載體爲爬蟲程序,則該請求的User-Agent爲爬蟲程序的身份標識。可以通過判斷該值來獲知該請求的載體究竟是基於哪款瀏覽器還是基於爬蟲程序。

  • 反爬機制:某些門戶網站會對訪問該網站的請求中的User-Agent進行捕獲和判斷,如果該請求的UA爲爬蟲程序,則拒絕向該請求提供數據。

  • 反反爬策略:將爬蟲程序的UA僞裝成某一款瀏覽器的身份標識。


2. requests模塊post請求


① 格式


response = request.post(
	url,

	headers = {},

	data = {},請求數據字典

)

② post請求得到響應內容json的兩種處理方法


  • post請求一般得到的響應內容是json數據
  • 處理json數據用到的模塊就是json模塊
  • 獲得的json數據本質就是一個json字符串

json兩種處理方法

- json.dumps(python的list或dict)-------->(返回值)----->json字符串
- json.loads(json字符串)------->(返回值)------------>python的list或dict

response對象自帶的json方法

  • response對象有一個方法response.json()--------->可以直接將獲取到的json字符串轉換成python的list或dict------->這個方法返回值就是python的list或dict
response.json() 可以直接將獲取到的json字符串轉換成python的list或dict

③ post請求實現案例


案例:百度翻譯

import requests

## 確定url
base_url = 'https://fanyi.baidu.com/sug'

## 封裝headers字典和data字典
kw = 'python'
data = {
 'kw': kw
}
headers = {
    ## 百度沒有反爬措施,所以不寫也行
    'content-length': str(len(data)),
    'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'origin': 'https://fanyi.baidu.com',
    'referer': 'https://fanyi.baidu.com/',
    'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
}

response = requests.post(base_url,headers=headers,data=data)

json_data = response.json()
print(response.json())

result = ''
for data in json_data["data"]:
    result += data['v'] + '\n'
print(result)

在這裏插入圖片描述
案例:有道翻譯

import requests

base_url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'

data = {
    'i': 'python',
    'from': 'AUTO',
    'to': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': '15722527593368',
    'sign': '6b72a0409791e6264fd9be055b2a752d',
    'ts': '1572252759336',
    'bv': 'd2685b66b612e42764cb7b20e19ecbe4',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'
}

headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Content-Length': '239',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': 'OUTFOX_SEARCH_USER_ID_NCOO=329725962.8668213; OUTFOX_SEARCH_USER_ID="[email protected]"; _ga=GA1.2.1184567758.1572184613; _gid=GA1.2.975310807.1572184613; JSESSIONID=aaa9OYhn0K6ouhYCiKr4w; ___rl__test__cookies=1572252759331',
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
}

response = requests.post(base_url,headers=headers,data=data)

print(response.text)

發現問題:爬取完後,我們發現,我們無法修改關鍵詞,只可以查詢詞彙爲我們一開始輸入的固定單詞,因此,我們需要找到辦法可以使查出所有詞彙。一般這種情況,由於某些參數的隨時變化,我們需要在有道上翻譯多個詞來對比參數有哪些不同

解決思路如下:

  • 處理post請求參數怎麼解決換了參數就請求不到的問題

  • 思路

    • 對比。比對data字典哪些參數是不一樣的
    • 想辦法找到這些參數的生成原理

案例:有道翻譯,完善後
在這裏插入圖片描述
知道是這三個參數不一樣,因此我們需要破解這三個參數,找到這些參數的生成原理,

常見的參數存放位置:

  • js中動態生成參數
  • 前端頁面(可能是隱藏的hidden標籤,都是固定寫死的)
  • 可以通過ajax獲取一些參數

具體js文件爲(注意:要先刷新頁面)
在這裏插入圖片描述
經過查詢此處爲某個js代碼中的參數
在這裏插入圖片描述
修改參數
在這裏插入圖片描述
完善後代碼

import requests,hashlib,time,random

base_url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'

def get_md5(value):
    md5 = hashlib.md5()
    md5.update(bytes(value,encoding='utf-8'))
    return md5.hexdigest()
value = 'python'
salt = str(int(time.time()*1000)) + str(random.randint(0,10))
sign = get_md5("fanyideskweb" + value + salt +  "n%A-rKaT5fb[Gy?;N5@Tj")
ts = str(int(time.time()*1000))


data = {
    'i': value,
    'from': 'AUTO',
    'to': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': salt,
    'sign': sign,
    'ts': ts,
    'bv': 'd2685b66b612e42764cb7b20e19ecbe4',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'
}

headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Content-Length': '239',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': 'OUTFOX_SEARCH_USER_ID_NCOO=329725962.8668213; OUTFOX_SEARCH_USER_ID="[email protected]"; _ga=GA1.2.1184567758.1572184613; _gid=GA1.2.975310807.1572184613; JSESSIONID=aaa9OYhn0K6ouhYCiKr4w; ___rl__test__cookies=1572252759331',
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
}

response = requests.post(base_url,headers=headers,data=data)

print(response.text)

發佈了107 篇原創文章 · 獲贊 43 · 訪問量 7068
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章