python 爬蟲

落落的学习發表於2024-04-20

python 爬蟲

1.開發工具

pycharm:

https://pan.baidu.com/s/1s_bkgDT0QxNTQY07LnQRWQ?pwd=2dlb
提取碼:2dlb

python3

VSCode

2.第一個爬蟲的開發

from urllib.request import urlopen

url = "http://www.baidu.com"

resp = urlopen(url)
#print(resp.read().decode("utf-8")) #獲取頁面原始碼

#將頁面原始碼儲存到當前目錄下的 mybaidu.html 檔案中
with open("mybaidu.html", mode="w", encoding="utf-8") as f:
    f.write(resp.read().decode("utf-8"))

3.瀏覽器工具的使用

推薦 Chrome

快捷鍵:F12

Chrome 各模組使用

Elements 模組:與頁面原始碼(Ctrl + U)中的程式碼可能會不一樣,該模組做參考

Console 模組:控制檯,執行 JavaScript 程式碼

Sources 模組:整個頁面所需要使用到的所有資源,程式碼、指令碼等

Network 模組:整個網頁使用的所有資源,請求、響應、圖片、js等的載入

  XHR:篩選出載入資料的網路請求(主要)

  Perserve log:能夠儲存之前的網路請求(勾選)

Performance 模組:

4.HTTP 協議

HTTP(Hyper Text Transfer Protocol):超文字傳輸協議

請求:

請求行 -> 請求方式(get/post)請求 URL 地址 協議
請求頭 -> 放一些伺服器要使用的附加資訊

請求體 -> 一般放一些請求引數

響應:

狀態行 -> 協議 狀態碼
響應頭 -> 放一些客戶端要使用的一些附加資訊

響應體 -> 伺服器返回的真正客戶端要使用的內容(HTML、json)等

請求頭中最常見的一些重要內容(爬蟲需要):

User-Agent:請求載體的身份標識(用什麼傳送的請求)
Referer:防盜鏈(該請求是從哪個頁面來的,反爬會用到)
Cookie:本地字串資料資訊(使用者登入資訊,反爬的 token)

響應頭中的一些重要的內容:

Cookie:本地字串資料資訊(使用者登入資訊,反爬的 token)
各種神器的莫名其妙的字串(需要經驗判斷,一般是 token 字樣,防止各種攻擊和反爬)

5.requests 模組入門

5.1.模組安裝

模組安裝:pip install requests

如果安裝速度慢的話,可以改用國內源進行下載:

臨時使用:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests
設為預設:
pip install pip -U
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

5.2.使用

python 指令碼的命名不要和模組相同

import requests

#爬取百度的頁面原始碼
url = "http://www.baidu.com"
resp = requests.get(url)
resp.encoding = "utf-8" #設定編碼方式
print(resp.text) #拿到頁面原始碼

5.3.UA 頭反爬

import requests

content = input("請輸入你要檢索的內容:")
url = f"https://www.sogou.com/sie?query={content}"

headers = {
    #新增一個請求資訊,UA 頭
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
#處理一個小小的反爬
resp = requests.get(url, headers=headers)
print(resp.text)

#print(resp.request.headers) #可以檢視到預設的請求頭資訊

5.4.GET 請求方法-get,params

get 函式,params 傳遞引數

import requests

url = "https://movie.douban.com/j/chart/top_list"

data = {
    "type": "13",
    "interval_id": "100:90",
    "action": "",
    "start": "0",
    "limit": "20"
}

header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"}
resp = requests.get(url, params=data, headers=header)
#print(resp.text) #拿到的是文字字串
print(resp.request.url) #輸出請求的 url
print(resp.json()) #直接拿到的是 json 資料

5.5.POST 請求方法

post 函式,data 傳遞引數

import requests

url = "https://movie.douban.com/j/chart/top_list"

data = {
    "kw":input("請輸入一個單詞:")
}

resp = requests.post(url, data=data)
#print(resp.text) #拿到的是文字字串
print(resp.json()) #直接拿到的是 json 資料

6.資料解析

四種解析方式

  • re 解析(正則)
  • bs4 解析
  • xpath 解析
  • pyquery 解析

四種方式可以混合使用

7.正規表示式

線上測試正規表示式:https://tool.oschina.net/regex/

7.1.常用元字元

元字元:具有固定含義的特殊符號,一個元字元匹配一位

.:匹配除換行符以外的任意字元
\w:匹配字母或數字或下劃線
\s:匹配任意的空白符
\d:匹配數字
\n:匹配一個換行符
\t:匹配一個製表符

^:匹配以某字串開頭的,^test
$:匹配以某字串結尾的,test$

\W:匹配非字母或數字或下劃線
\D:匹配非數字
\S:匹配非空白符
a|b:匹配字元a,或字元b
():匹配括號內的表示式,也表示一個組
[...]:匹配字元組種的字元
[^...]:匹配除了字元組中的字元的左右字元

7.2.量詞

量詞:控制前面的元字元出現的次數

*:重複零次或多次
+:重複一次或多次
?:重複零次或一次
{n}:重複 n 次
{n,}:重複 n 次或更多次
{n,m}:重複至少 n 次且最多 m 次

7.3.貪婪匹配和惰性匹配

.*:貪婪匹配(儘可能多地匹配)
>*?:惰性匹配(儘可能少地匹配)

在爬蟲中用得最多的就是惰性匹配

案例

str:玩兒吃雞遊戲,晚上一起打遊戲,幹嘛呢?打遊戲啊

reg:玩兒.*?遊戲
匹配結果:玩兒吃雞遊戲

reg:玩兒.*遊戲
匹配結果:玩兒吃雞遊戲,晚上一起打遊戲,幹嘛呢?打遊戲

8.re 模組

8.1.基本使用

內建模組

import re

#result = re.findall(r"\d+", "我今年18歲,存款280000000塊")
#print(result)

#重點
# result = re.finditer(r"\d+", "我今年18歲,存款280000000塊")
# for item in result: #從迭代器中拿到內容
#     print(item.group()) #從匹配到地結果中拿到資料

#search 只會匹配到第一次匹配地內容
# result = re.search(r"\d+", "我叫張三,今年20歲,我地班級是5年4班")
# print(result.group())

#match 在匹配時,是從字串的開頭進行匹配的,類似在正則前面加上了 ^
# result = re.match(r"\d+", "我叫張三,今年20歲,我地班級是5年4班")
# print(result)

#預載入,提前把正則物件載入完畢
obj = re.compile(r"\d+")
#直接使用載入好的正則
result = obj.findall("我叫張三,今年20歲,我地班級是5年4班")
print(result)

獲取資料

import re

#想要提取資料,必須用小括號括起來,可以單獨起名字
#(?P<名字>正則)
#提取資料的時候,需要 group("名字")
s = """
<div class='西遊記'><span id='10010'>中國聯通</span></div>
<div class='西遊記'><span id='10086'>中國移動</span></div>
"""
obj = re.compile(r"<span id='(?P<id>\d+)'>(?P<name>.*?)</span>")

result = obj.finditer(s)
for item in result:
    id = item.group("id")
    print(id)

    name = item.group("name")
    print(name)

8.2.案例1-豆瓣top250

先檢視想獲取的資料是否在頁面原始碼中

"""
思路:
1.拿到頁面原始碼
2.編寫正則,提取頁面資料
3.儲存資料
"""
import requests
import re

f = open("top250.csv", mode="w", encoding="utf-8")

headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"}

for i in range(1, 11):
    url = f"https://movie.douban.com/top250?start={(i-1)*25}&filter="
    resp = requests.get(url, headers=headers)
    url = "https://movie.douban.com/top250"
    # resp.encoding = "utf-8" #解決中文亂碼問題
    pageSource = resp.text
    # print(pageSource)

    # 編寫正規表示式
    # re.S 可以讓正則中的 . 匹配換行符
    obj = re.compile(r'<div class="item">.*?<span class="title">'
                     r'(?P<name>.*?)</span>.*?<p class="">.*?導演: '
                     r'(?P<dao>.*?)&nbsp;.*?<br>'
                     r'(?P<year>.*?)&nbsp;.*?<span class="rating_num" property="v:average">'
                     r'(?P<score>.*?)</span>.*?<span>(?P<num>.*?)人評價</span>', re.S)

    # 進行正則匹配
    result = obj.finditer(pageSource)
    for item in result:
        name = item.group("name")  # 拿結果
        dao = item.group("dao")
        year = item.group("year").strip()  # 去除字串左右兩端空白
        score = item.group("score")
        num = item.group("num")
        f.write(f"{name},{dao},{year},{score}\n")  # 可以更換成 csv 模組,進行資料寫入
        # print(name, dao, year, score, num)

f.close()
resp.close()
print("豆瓣top250提取完畢")

#如何翻頁提取
#(頁數-1)*25 => start

8.3.案例2-獲取電影天堂電影名稱及對應下載連結

"""
思路:
1.提取到主頁面中的每一個電影的背後的那個 url 地址
    1.1.拿到 “2024必看熱片” 那一塊的 HTML 程式碼
    1.2.從剛才拿到的 HTML 程式碼中提取到 href 值
2.訪問子頁面,提取到電影的名稱以及下載連結
    2.1.拿到子頁面的頁面原始碼
    2.2.資料提取
"""
import requests
import re

url = "https://www.dy2018.com/"
resp = requests.get(url)
resp.encoding = "gbk"
#print(resp.text)

#1.1.提取 2024必看熱片 部分的 HTML 程式碼
obj1 = re.compile(r"2024必看熱片.*?<ul>(?P<html>.*?)</ul>", re.S)
result1 = obj1.search(resp.text)
html = result1.group("html")

#1.2.提取a標籤中的href值
obj2 = re.compile(r"<li><a href='(?P<href>.*?)' title", re.S)
result2 = obj2.finditer(html)


obj3 = re.compile(r'<div id="Zoom">.*?◎片  名(?P<moive_name>.*?)<br />.*?'
                  r'<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="'
                  r'(?P<download>.*?)">', re.S)

for item in result2:
    #拼接出子頁面的url
    child_url = url.strip("/") + item.group("href")
    child_resp = requests.get(child_url)
    child_resp.encoding = "gbk"

    result3 = obj3.search(child_resp.text)
    movie_name = result3.group("moive_name")
    download = result3.group("download")
    print(movie_name, download)

9.CSS 基礎語法

9.1.CSS 語法規則

透過 style 屬性來編寫樣式

透過 style 標籤,然後使用選擇器的形式來編寫樣式

在 CSS 檔案中編寫樣式,透過 link 引入該檔案

9.2.CSS 選擇器

id 選擇器:#

標籤選擇器:標籤

類選擇器:.

選擇器分組:,

後代選擇器:空格

子選擇器:>

相鄰選擇器:+

屬性選擇器:[屬性=值]

10.bs4 解析

10.1.基本使用

安裝:pip install bs4

from bs4 import BeautifulSoup

html = """
<ul>
    <li><a href="zhangwuji.com">張無忌</li>
    <li id="abc"><a href="zhouxingchi.com">周星馳</li>
    <li><a href="zhubajie.com">豬八戒</li>
    <li><a href="wuzetian.com">武則天</li>
    <a href="jinmaoshiwang.com">金毛獅王</a>
</ul>
"""

#1.初始化 BeautifulSoup 物件
page = BeautifulSoup(html, "html.parser")
#page.find("標籤名", attrs={"屬性":"值"}) #查詢某個元素,只會找到一個結果
#page.find_all("標籤名", attrs={"屬性":"值"}) #找到一堆結果

# li = page.find("li", attrs={"id":"abc"})
# a = li.find("a")
# print(a.text) #拿文字
# print(a.get("href")) #拿屬性值:.get("屬性名")

li_list = page.find_all("li")
for li in li_list:
    a = li.find("a")
    text = a.text
    href = a.get("href")
    print(text, href)

10.2.案例1-新發地菜價

import requests
from bs4 import BeautifulSoup

f = open("新發地菜價.csv", mode="w", encoding="utf-8")

url = "http://www.xinfadi.com/marketanalysis/0/list/1.shtml"
resp = requests.get(url)
#初始化物件
page = BeautifulSoup(resp.text, "html.parser")
table = page.find("table", attrs={"class":"hq_table"})
trs = table.find_all("tr")[1:] #拿到除第一行外的所有 tr
for tr in trs:
    tds = tr.find_all("td")
    name = tds[0].text #品名
    low = tds[1].text #最低價
    avg = tds[2].text #平均價
    hig = tds[3].text #最高價
    kind = tds[4].text #規格
    dan = tds[5].text #單位
    date = tds[6].text #釋出日期
    #print(name, low, avg, hig, dan, date)
    f.write(f"{name},{low},{avg},{hig},{dan},{date}")
f.close()
resp.close()
print("爬取成功")

10.3.案例2-圖片抓取

import requests
from bs4 import BeautifulSoup

"""
注意:
子頁面的 url 如果開頭是 /,直接在前面拼接上域名即可
子頁面的 url 不是 / 開頭,此時需要找到主頁面的 url,去掉最後一個 / 後面的所有內容,和當前獲取的 url 進行拼接
"""
domain = "https://www.umei.net"
url = "https://www.umei.net/bizhitupian/xiaoqingxinbizhi/"
resp = requests.get(url)
resp.encoding = "utf-8"

n = 1 #圖片名稱

main_page = BeautifulSoup(resp.text, "html.parser")
a_list = main_page.find_all("a", attrs={"calss":"TypeBigPics"})
for a in a_list:
    href = a.get("href")
    child_url = domain + href
    child_resp = requests.get(child_url) #請求到子頁面
    child_resp.encoding = "utf-8"
    # print(child_resp.text)
    # break #測試以下,如果亂碼需要進行編碼設定
    #子頁面的 bs 物件
    child_bs = BeautifulSoup(child_resp.text, "html.parser")
    div = child_bs.find("div", attrs={"class":"ImageBody"})
    img_src = div.find("img").get("src") #拿到圖片的下載路徑
    #print(img_src)
    #下載圖片
    img_resp = requests.get(img_src)
    with open(f"{n}.jpg", mode="wb") as f: #注意,此時寫入到檔案的是位元組,所以必須是 wb
        f.write(img_resp.content) #把圖片資訊寫入檔案
    print(f"第{n}張圖片下載完畢")
    n += 1
import requests
from bs4 import BeautifulSoup

domain = "https://www.umei.net"
url = "https://www.umei.net/tags/qingchun/"
resp = requests.get(url)
#print(resp.text) #測試網頁是否正常顯示(如:完整拉取、中文是否亂碼)

n = 1

main_page = BeautifulSoup(resp.text, "html.parser")
l_list = main_page.find_all("li", {"class": "i_list list_n2"})

for l in l_list:
    a_url = l.find("a")["href"]
    child_url = domain + a_url
    child_resp = requests.get(child_url)
    child_resp.encoding = "utf-8"
    child_bs = BeautifulSoup(child_resp.text, "html.parser")
    div = child_bs.find("div", {"class": "image_div"})
    img_src = div.find("img")["src"]
    img_resp = requests.get(img_src, verify=False)
    name = main_page.find("title")
    #print(name.text)
    with open(f"{name.text}.jpg", "wb") as f:
        f.write(img_resp.content)
    print(f"第{n}張圖片下載完畢")
    n += 1
    # break
resp.close()
print("爬取完畢")

11.xpath 解析

11.1.基礎使用

XPath 是一門在 XML 文件中查詢資訊的語言

<book>
    <id>1</id>
    <name>野花遍地香</name>
    <price>1.23</price>
    <author>
        <nick>周大強</nick>
        <nick>周芷若</nick>
    </author>
</book>

book、id、name、price。。。都被稱為節點

id、name、price、author 被稱為 book 的子節點

安裝模組:pip install lxml

匯入模組兩種方式:

from lxml import etree

報錯可以考慮以下匯入方式:
from lxml import html
etree = html.etree
from lxml import etree

xml = """
<book>
    <id>1</id>
    <name>野花遍地香</name>
    <price>1.23</price>
    <nick>臭豆腐</nick>
    <author>
        <nick id="10086">周大強</nick>
        <nick id="10010">周芷若</nick>
        <nick class="jay">周杰倫</nick>
        <nick class="jolin">蔡依林</nick>
        <div>
            <nick>惹了</nick>
        </div>
    </author>
    <partner>
        <nick id="ppc">胖胖陳</nick>
        <nick id="ppbc">胖胖不陳</nick>
    </partner>
</book>
"""
#此時練習只能用 XML
et = etree.XML(xml)
#result = et.xpath('/book') #找根節點的 book
#result = et.xpath('/book/name')
# result = et.xpath('/book/name/text()')[0] #text():拿文字,[0]表示取出文字內容
# result = et.xpath('/book//nick') # // 表示的所有的子孫後代
# result = et.xpath('//book/*/nick/text()') #* 萬用字元
# result = et.xpath('//book/*/*/nick/text()')
#result = et.xpath('//book/author/nick[@class="jay"]/text()') #[] 表示屬性篩選,@屬性名=值
result = et.xpath('//book/partner/nick/@id') #最後一個 / 表示拿到 nick 中的 id 的內容,@屬性,可以直接拿到屬性值
print(result)
from lxml import etree

#xpath 處理 html

html = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Title</title>
</head>
<body>
    <ul>
        <li><a href="http://www.baidu.com">百度</a></li>
        <li><a href="http://www.google.com">谷歌</a></li>
        <li><a href="http://www.sougou.com">搜狗</a></li>
    </ul>
    <ol>
        <li><a href="feiji">飛機</a></li>
        <li><a href="dapao">大炮</a></li>
        <li><a href="huoche">火車</a></li>
    </ol>
    <div class="job">李嘉誠</div>
    <div class="common">胡辣湯</div>
</body>
</html>
"""

et = etree.HTML(html)
# li_list = et.xpath('/html/body/ul/li[2]/a/text()')
# print(li_list)

li_list = et.xpath('//li')
for li in li_list:
    href = li.xpath('./a/@href') # ./ 表示當前節點
    text = li.xpath('./a/text()')
    print(href, text)
    # 後續的爬蟲工作...

11.2.案例1-豬八戒網站

"""
1.拿到頁面原始碼
2.從頁面原始碼中提取需要的資料、價格、名稱、公司名稱
"""
import requests
from lxml import etree

url = "https://www.zbj.com/fw/?k=saas"
resp = requests.get(url)
resp.encoding = "utf-8"
#print(resp.text)

#提取資料
et = etree.HTML(resp.text)
divs = et.xpath('//div[@class="search-result-list-service"]/div')

for div in divs:
    #此時的 div 就是一條資料,對應一個商品資訊
    # 商品價格
    price = div.xpath('./div/div[3]/div/span/text()')
    # 去除價格為空的情況
    if not price:
        continue
    price = price[0]
    company = div.xpath('./div/a/div[2]/div[1]/div/text()')[0]
    name = div.xpath('./div/div[3]/div[2]/a//text()') # // 表示提取 a 的所有文字
    name = "".join(name)
    print(name, price, company)

11.3.小技巧:找 XPath

F12 下的 Elements 模組

選擇需要查詢的程式碼

確定 xpath 路徑:

divs = et.xpath('//div[@class="search-result-list-service"]/div')

然後按上述操作,尋找到想要爬取的資料的程式碼位置,如,價格:

在價格的程式碼上滑鼠右鍵,選擇 Copy -> Copy XPath

然後對複製下來的 xpath 進行調整成自己需要的

12.pyquery 解析

12.1.基礎使用

pyquery 可以對 HTML 結構進行修改

from pyquery import PyQuery

html = """
<HTML>
    <div class="aaa">噠噠噠</div>
    <div class="bbb">嘟嘟嘟</div>
</HTML>
"""

p = PyQuery(html)

# 在xxx標籤後新增 xxx 新標籤
#p("div.aaa").after("""<div class="ccc">吼吼吼</div>""")
# 在 xxx 標籤裡面 新增
#p("div.aaa").append("""<span>yyy</span>""")

#修改標籤屬性值及新增屬性
# p("div.bbb").attr("class", "aaa")
# p("div.bbb").attr("id", '12306') #前提是該標籤沒有該屬性

# p("div.bbb").remove_attr("id") #刪除屬性
# p("div.bbb").remove() #刪除標籤
print(p)

12.2.案例-汽車之家

目標網站程式碼更變,下面程式碼不適用

"""
1.提取頁面原始碼
2.解析頁面原始碼,提取資料
"""
import requests
from pyquery import PyQuery

def get_page_source(url):
    resp = requests.get(url)
    resp.encoding = "utf-8"
    print(resp.text)

def parse_page_source(html):
    doc = PyQuery(html)
    mt_list = doc(".mt-10").items() #class="mt-10"
    for mt in mt_list: # 拿到每一個 mt
        # 判斷是否有汽車經銷商
        if not mt("div > dl:nth-child(3) > dt:contains(購車經銷商"):
            mt("div > dl:nth-child(2)").after(PyQuery("""
            html 相關程式碼"""))

        # 提取購買的車型
        # 想要在已經提取的內容中獲取第一個怎麼辦 eq(0)
        # nth-child(1) 在 css 進行選擇的時候,選取第一個位置的內容
        chexing = mt("div > dl:nth-child(1) > dd").eq(0).text().replace("\n", "").replace(" ","")
        didian = mt("div > dl:nth-child(2) > dd").text()
        shijian = mt("div > dl:nth-child(4) > dd").text()
        jiage = mt("div > dl:nth-child(5) > dd").text().replace(" 萬元", "")
        youhao = mt("div > dl:nth-child(6) > dd > p:nth-child(1)").text().replace(" 升/百公里", "")
        gonglishu = mt("div > dl:nth-child(6) > dd > p:nth-child(2)").text().replace(" 公里", "")
        other = mt("div > div > dl > dd").text().split()
        #print(chexing)
        #儲存到檔案中

def main(): #入口函式
    url = "https://k.autohome.com.cn/146/"
    #1.提取頁面原始碼
    html = get_page_source(url)
    #2.解析頁面原始碼,提取資料
    parse_page_source(html)

if __name__ == '__main__':
    main()

13.requests 進階

13.1.模擬使用者登入

# 登入 -> 得到 cookie
# 帶著 cookie 去請求到書架 url -> 書架上的內容
# 必須把上面兩個操作連起來
# 可以使用 session 進行請求 -> 可以任務 session 是一連串的請求。在這個過程中的 cookie 不會丟失
import requests

# 會話
session = requests.session()
data = {"loginName": "173xxxx36",
        "password": "xxx08"}
# 1.登入
url = "https://passport.17k.com/ck/user/login"
resp = session.post(url, data=data)
# print(resp.cookie) # cookie

# 2.拿書架上的資料
# session 中是有 cookie 的
resp2 = session.get('https://user.17k.com/ck/author2/shelf?page=1&appKey=2406394919')
print(resp2.text)

# 直接從登入頁面中拿取cookie獲取資料
# resp = requests.get("https://user.17k.com/ck/author2/shelf?page=1&appKey=2406394919", headers={"Cookie":"cookie 值"}) # print(resp.text)

13.2.防盜鏈

# 1.拿到 contId
# 2.拿到 videoStatus 返回的json -> srcURL
# 3.srcURL 裡面的內容進行修整
# 4.下載影片
import requests

# 拉取影片的網址
url = "https://www.pearvideo.com/video_1721605"
contId = url.split("_")[1]

videoStatusUrl = f"https://www.pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.6952007481227842"
headers = {
    "User-Agent": "Mozilla/5",
    # 防盜鏈
    "Referer": url
}

resp = requests.get(videoStatusUrl, headers=headers)
dic = resp.json()

srcUrl = dic['videoInfo']['videos']['srcUrl']
systemTime = dic['systemTime']
srcUrl = srcUrl.replace(systemTime, f"cont-{contId}")

# 下載影片
with open("a.mp4", "wb") as file:
    file.write(requests.get(srcUrl).content)

# https://video.pearvideo.com/mp4/adshort/20210301/cont-1721692-15618910_adpkg-ad_hd.pm4 真實連結
# https://video.pearvideo.com/mp4/adshort/20210301/1614588366486-15618910_adpkg-ad_hd.pm4 拿到的連結

13.3.代理

# 代理,可以使用第三方的機器來代理你的請求
import requests

# https://www.kuaidaili.com/free/intr

url = "http://www.baidu.com"

# 準備代理資訊
proxy = {
    "http": "http://123.233.245.158:9443",
    "https": "https://123.233.245.158:9443"
}

resp = requests.get(url, proxies=proxy)
resp.encoding = "utf-8"
print(resp.text)

接入第三方

import requests

def get_ip():
    # 有待完善,如果代理 IP 都用完了,怎麼辦(再請求一編)
    url = "第三方生成的 API 連結"
    resp = requests.get(url)
    ips = resp.json()
    for ip in ips['data']['proxy_list']: #拿到每一個ip
        yield ip # 一個一個地返回 IP
def spider():
    url = "http://www.baidu.com/"
    while 1:
        try:
            proxy_ip = next(gen) # 拿到代理 IP
            proxy = {
                "http": "http://" + proxy_ip,
                "https": "http://" + proxy_ip
            }
            resp = requests.get(url, proxies=proxy)
            resp.encoding = "utf-8"
            return resp.text
        except:
            print("報錯了.")

if __name__ == '__main__':
    gen = get_ip() # gen 就是代理 IP 的生成器
    for i in range(10):
        spider()

相關文章