1. 程式人生 > 其它 >爬蟲02--requests庫其他操作、免費代理池和案例

爬蟲02--requests庫其他操作、免費代理池和案例

昨日回顧

1 爬蟲介紹
    -模擬傳送http請求---》獲取到資料(html,json,圖片,視訊)---》資料清洗----》入庫
    
2 請求庫:requests模組
    -跟其他服務互動,使用requests模組傳送請求呼叫
    -postman:或使用requests完全自己寫
    
3 傳送get請求
4 傳送get請求,地址中帶引數
    -直接拼在路徑中  
    -params引數傳入,字典
    -url編碼和解碼:中文編成url的編碼形式
5 傳送get請求,攜帶請求頭
    -headers引數
    -user-agent:客戶端型別
    -referer:上一個地址
    
6 傳送請求,攜帶cookie
    -請求頭
    -以引數形式攜帶
        
7 傳送post請求
    -地址中帶資料:params引數傳入
    -請求頭中帶:headers
    -請求體中:data={}(urlencoed格式),json={}
    
8 Respons物件屬性,引數
    -text:響應的body體,轉成了字串
    -content:響應體的二進位制(圖片,視訊)
    -iter_content:圖片,視訊,迴圈儲存
    -編碼
    -cookies:一旦登入成功,這個cookies就是認證後的cookies
    -.json() :把返回的json格式字串直接轉成字典形式
        
9 編碼問題
	
# 10 request.session的使用
    session = request.session()
    使用session物件,傳送請求後,會保持cookie,以後不用每次攜帶cookie

今日內容

1.requests之ssl,超時設定,認證設定,處理異常,上傳檔案 (瞭解)

# http+ssl=https :傳輸過程中加密了---》截獲到,無法解密
# ssl證書:第三方證書

# 證書驗證(大部分網站都是https)
import requests
respone=requests.get('https://www.12306.cn') # 如果是ssl請求,首先檢查證書是否合法,不合法則報錯,程式終端


# 1:強制使用http連線,不驗證證書  (去掉報錯,但是會報警告)
import requests
respone=requests.get('https://www.12306.cn',verify=False) # 不驗證證書,報警告,返回200
print(respone.status_code)

# 2:去掉報錯,並且去掉警報資訊
import requests
from requests.packages import urllib3
urllib3.disable_warnings() # 關閉警告
respone=requests.get('https://www.12306.cn',verify=False)
print(respone.status_code)

# 3:攜帶證書 (證書, 祕鑰)
# 很多網站都是https,但是不用證書也可以訪問,大多數情況都是可以攜帶也可以不攜帶證書
# 知乎\百度等都是可帶可不帶
# 有硬性要求的,則必須帶,比如對於定向的使用者,拿到證書後才有許可權訪問某個特定網站
import requests
respone=requests.get('https://www.12306.cn',cert=('/path/server.crt','/path/key'))
print(respone.status_code)
# 超時設定

import requests
respone=requests.get('http://127.0.0.1:8000',timeout=3)
print(respone.status_code)
# 認證設定(瞭解)
# 官網連結:http://docs.python-requests.org/en/master/user/authentication/

# 舊時的認證 (現在的認證,都是post請求)
    彈出一個框,要求你輸入使用者名稱密碼(與alter很類似),此時是無法獲取html的,但本質原理是拼接成請求頭髮送

# 老款的路由器的認證,公司內部可能會看到
import requests
from requests.auth import HTTPBasicAuth
r=requests.get('xxx',auth=HTTPBasicAuth('user','password'))
print(r.status_code)

# HTTPBasicAuth可以簡寫為如下格式
import requests
r=requests.get('xxx',auth=('user','password'))
print(r.status_code)
# 處理異常

import requests
from requests.exceptions import *
try:
    respone=requests.get('http://127.0.0.1:8000',timeout=3)
    print(respone.status_code)
except ReadTimeout:
    print('===:')
except ConnectionError: # 網路不通
    print('-----')
except Timeout:
    print('aaaaa')
except RequestException:
    print('Error')
except Exception as e:
    print(e)   
# 上傳檔案 
import requests
files={'file':open('a.jpg','rb')}
respone=requests.post('http://httpbin.org/post',files=files)  # formdata格式
print(respone.status_code)

2.requests使用代理

# 為什麼使用代理?
    -網站,訪問頻率過高,封ip,限制ip訪問次數(後端頻率類)
# 使用代理,隱藏訪問者ip,正向代理
    -代理伺服器
    -免費的:不穩定,不好用
    -收費:穩定,好用
    
    
import requests

proxies = {'http': 'http://117.68.194.189:1133', }
respone=requests.get('http://127.0.0.1:8000/',proxies=proxies)
print(respone.text)

3.搭建免費代理池

# 本地搭建專案
  專案地址: https://hub.xn--p8jhe.tw/jhao104/proxy_pool

1.git clone https://github.com/jhao104/proxy_pool.git
2.pip3 install -r requirements.txt
3.修改setting.py 中的redis連線
4.執行
# 啟動排程程式
python proxyPool.py schedule
# 啟動webApi服務
python proxyPool.py server


# 或直接使用該專案的測試地址返回的ip代理 

# 簡單使用
import requests

proxy = requests.get('http://demo.spiderpy.cn/get' ).json().get("proxy")
respone=requests.get('http://127.0.0.1:8000/',proxies={"http": "http://{}".format(proxy))
print(respone.text)

# 封裝一下
import requests

def get_proxy():
    return requests.get("http://127.0.0.1:5010/get/").json()
                                                       
def delete_proxy(proxy):
    requests.get("http://127.0.0.1:5010/delete/?proxy={}".format(proxy))

# your spider code

def getHtml():
    # ....
    retry_count = 5
    proxy = get_proxy().get("proxy")
    while retry_count > 0:
        try:
            html = requests.get('http://www.example.com', proxies={"http": "http://{}".format(proxy)})
            # 使用代理訪問
            return html
        except Exception:
            retry_count -= 1
                                                       
    # 刪除代理池中代理
    delete_proxy(proxy)
    return None      

4.爬取梨視訊

import requests
import re


# 分析網址規律:?reqType=5&categoryId=9&start=0   文章分類id  文章起始位置
res = requests.get('https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=9&start=0')
print(res.text)  # 返回的xml資料

# 解析資料:視訊文章id地址
video_list = re.findall('<a href="(.*?)" class="vervideo-lilink actplay">', res.text)
print(video_list)

# 拼接域名,獲取視訊的真正地址
for video in video_list:
    video_id = video.split('_')[-1]  # 視訊id
    video_url = 'https://www.pearvideo.com/' + video  # 視訊文章詳情頁地址   
    
    # res=requests.get(video_url)   # 該請求就不用訪問了,直接訪問那個Ajax的請求
    # print(res.text)
    # 直接訪問視訊文章詳情頁地址,沒有返回MP4格式的視訊地址
    # 該網站規則時,訪問該地址時,自動再發一個Ajax獲取視訊真正地址
    
    # 故需要,模擬傳送這個Ajax請求 (https://www.pearvideo.com/videoStatus.jsp?contId=視訊id&mrd=0.4930470461853751)
    # 訪問發現:
      瀏覽器直接訪問 和 從網站詳情頁訪問  返回的資料不一樣
      都是瀏覽器操作 說明User-Agent、cookie是一樣的,那就是請求頭的問題了 (對比發現:指定了referer)
    

    # 第一層反爬:需要帶referfer頭   # 動態自己拼
    header = {
        'Referer': 'https://www.pearvideo.com/%s' % video
    }
  
    res = requests.get('https://www.pearvideo.com/videoStatus.jsp?contId=%s&mrd=0.4930470461853751' % video_id,
                       headers=header)

    mp4_url = res.json()['videoInfo']['videos']['srcUrl']
    
    # 第二層反爬:需要將mp4_url地址進行部分替換
    mp4_url = mp4_url.replace(mp4_url.split('/')[-1].split('-')[0], 'cont-%s' % video_id)

    # 下載視訊
    res_video=requests.get(mp4_url)
    with open('./viode/%s.mp4'%video_id,'wb') as f:
        for line in res_video.iter_content(1024):
            f.write(line)


'''
不能播放的:
https://video.pearvideo.com/mp4/third/20211014/    1634271064903   -11980839-104649-hd.mp4
能播放的:
https://video.pearvideo.com/mp4/third/20211014/    cont-1743691   -11980839-104649-hd.mp4

5.爬取汽車之家

# bs4解析html
# pip3 install  beautifulsoup4

import requests
from bs4 import BeautifulSoup

res = requests.get('https://www.autohome.com.cn/news/1/#liststart')
# print(res.text)

# 第一個引數,要解析的文件,第二個引數,解析的解析器('html.parser')
soup = BeautifulSoup(res.text, 'html.parser')

# res=soup.find_all(class_='article',name='ul')
ul_list=soup.find_all(name='ul')
for ul in ul_list:
    li_list=ul.find_all(name='li')
    for li in li_list:
        h3=li.find(name='h3')
        if h3:
            title=h3.text  # 拿出h3標籤的文字內容
            # print(title)
            url='http:'+li.find('a').attrs['href']
            # print(url)
            img_url=li.find(name='img').attrs['src']
            # print(img_url)
            desc=li.find('p').text
            # print(desc)

            print('''
            新聞標題:%s
            新聞連線:%s
            新聞圖片:%s
            新聞摘要:%s
            
            '''%(title,url,img_url,desc))
            
            # 入庫:mysql,建表,欄位,pymysql