小豬的Python學習之旅 —— 2.爬蟲初涉

coder-pig發表於2018-01-11

引言

本節開始學習Python爬蟲,為什麼直接開始學爬蟲?因為實用性高啊, 練手專案多(那麼多網站可以爬),後面還可以做資料分析等等,還有最終 要的,可以扒很多小姐姐到硬碟裡啊。什麼是爬蟲?我的理解: 模擬使用者使用瀏覽器請求網站,然後通過一些手段獲取到想要的資訊; 比如在一個小網站上看到了很多漂亮的小姐姐圖片,你想把他們都存 到你的硬碟裡,每天沒事就拿出來把玩一下。

如果你不會爬蟲,你只能重複地

右鍵圖片->圖片另存為->選擇資料夾->改下圖片名->儲存

呆得一匹,如果你學會了爬蟲,你只需要花幾分鐘編寫爬蟲指令碼: 然後執行下Py指令碼,你可以去玩把跳一跳,回來就可以看到小姐姐 們都乖乖地趟在你的硬碟裡了:

小豬的Python學習之旅 —— 2.爬蟲初涉

對的,就是那麼酷炫,程式設計師就應該做些酷酷的事! 關於Python爬蟲,主要由兩個部分組成:

  • 1.能夠拿到正確的目標網站的網頁原始碼
  • 2.通過一些技術手段拿到想要的目標資訊

依次說下這兩個部分吧,先是拿到正確網頁原始碼

並不是所有的原始碼都是躺在那裡等你直接扒的,很多網站都會有 反爬蟲策略,比如:需要點選閱讀全文才能載入所有內容;資料 使用Js動態生成(圖片站點尤多);這還是不需要登入的情況,有些 站點需要登入後才能訪問,模擬登入驗證碼可以卡死一堆人: 數字圖片模糊驗證計算數字運算驗證滑動條驗證滑動圖片驗證滑動壞塊完成拼圖驗證geetest那種人機驗證...

接著是通過技術手段拿到目標資訊

這個倒沒什麼,最多也就是Js動態生成網頁,這個可以通過後面學 的selenium來規避,反正瀏覽器顯示的是什麼樣,拿到的網頁原始碼 就是怎麼樣。(還有一種噁心的:把文字資料寫到圖片上,讓你抓到 圖片也無可奈何,可以使用ORC的一些庫進行文字識別,比如 tesseract-orc但是結果都是有些偏差的,還要自己另外處理...) 有正確的網頁原始碼了,基本上都是找到我們想要的資料的,學習 一些HTML,XML的解析庫就可以了,比如:BeautifulSouplxml等, 隨便掌握一個就好了,筆者學習的是BeautifulSoup(甜湯)

說下爬蟲學習路線吧:

1.先把基礎核心庫urllib學習一波; 2.接著學習一波BeautifulSoup來解析網頁資料; 3.學習正規表示式 4.使用Scrapy框架爬取資料 5.使用Selenium模擬瀏覽器 6.多執行緒抓取 等等...

關於爬蟲的基礎姿勢就瞭解到這裡,開始本節內容~


1.urllib模組詳解

用於操作URL的模組(庫,py3把urllib和urllib2合併到了一起) 爬網頁必須掌握的最基礎的東東。

1) 爬取網頁

import urllib.request
import urllib.parse
import json

# 爬取網頁資訊
html_url = "http://www.baidu.com"
html_resp = urllib.request.urlopen(html_url)

# 讀取全部,讀取一行可用readline(),多行返回列表的可用readlines()
html = html_resp.read() 
html = html.decode('utf-8')  # 解碼
print(html)

# 獲得其他資訊:
html_resp.info() # 獲得頭相關的資訊,HTTPMessage物件
html_resp.getcode() # 獲得狀態碼
html_resp.geturl() # 獲取爬取的url

# url中包含漢字是不符合URL標準的,需要進行編碼
urllib.request.quote('http://www.baidu.com') 
# 編碼後:http%3A//www.baidu.com

urllib.request.unquote('http%3A//www.baidu.com') 
# 解碼後:http://www.baidu.com
複製程式碼

2) 爬取二進位制檔案(圖片,音訊等)

# 下載圖片
pic_url = "http://static.zybuluo.com/coder-pig/agr9d5uow8r5ug8iafnl6dlz/1.jpg"
pic_resp = urllib.request.urlopen(pic_url)
pic = pic_resp.read()
with open("LeiMu.jpg", "wb") as f:
    f.write(pic)

# 也可以直接呼叫urlretrieve下載,比如下載音訊
music_url = "http://7xl4pr.com2.z0.glb.qiniucdn.com/" \
            "%E4%B8%83%E7%94%B0%E7%9C%9F%E4%B8%93%E5%8C%BA%2F%E4%" \
            "B8%AD%E6%96%87%E8%AF%BE%2F%E6%83%B3%E8%" \
            "B1%A1%E7%82%B9%E5%8D%A1%2F%2B6.mp3"
urllib.request.urlretrieve(music_url, "兒歌.mp3")
複製程式碼

3) 模擬Get請求與Post請求

PS:下面用到的**json模組**:用於將Python原始型別與json型別相互轉換,使用 如果是讀取檔案可以用:dump()和load()方法,字串的話用下述兩個:

dumps()編碼 [Python -> Json] dict => object      list, tuple => array      str => string      True => true int, float, int- & float-derived Enums => number      False => false     None => null

loads()解碼 [Json -> Python] object => dict     array => list     string => str     number (int) => int number(real) => float     true =>True     false => False     null => None

# 模擬Get
get_url = "http://gank.io/api/data/" + urllib.request.quote("福利") + "/1/1"
get_resp = urllib.request.urlopen(get_url)
get_result = json.loads(get_resp.read().decode('utf-8'))
# 這裡後面的引數用於格式化Json輸出格式
get_result_format = json.dumps(get_result, indent=2,
                               sort_keys=True,  ensure_ascii=False)
print(get_result_format)

# 模擬Post
post_url = "http://xxx.xxx.login"
phone = "13555555555"
password = "111111"
values = {
    'phone': phone,
    'password': password
}
data = urllib.parse.urlencode(values).encode(encoding='utf-8')
req = urllib.request.Request(post_url, data)
resp = urllib.request.urlopen(req)
result = json.loads(resp.read())    # Byte結果轉Json
print(json.dumps(result, sort_keys=True, 
                 indent=2, ensure_ascii=False)) # 格式化輸出Json
複製程式碼

4) 修改請求頭

有些網站為了避免別人使用爬蟲惡意採取資訊會進行一些反爬蟲的操作, 比如通過請求頭裡的User-Agent,檢查訪問來源是否為正常的訪問途徑, 我們可以修改請求頭來進行模擬正常的訪問。Request中有個headers引數, 有兩種方法進行設定: 1.把請求頭都塞到字典裡,例項化Request物件的時候傳入 2.通過Request物件的add_header()方法一個個新增

# 修改頭資訊
novel_url = "http://www.biqukan.com/1_1496/"
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '
                         'AppleWebKit/537.36 (KHTML, like Gecko)'
                         ' Chrome/63.0.3239.84 Safari/537.36',
           'Referer': 'http://www.baidu.com',
           'Connection': 'keep-alive'}
novel_req = urllib.request.Request(novel_url, headers=headers)
novel_resp = urllib.request.urlopen(novel_req)
print(novel_resp.read().decode('gbk'))
複製程式碼

5) 設定連線超時

# urlopen函式時新增timeout引數,單位是秒
urllib.request.urlopen(novel_req, timeout=20)
複製程式碼

6) 延遲提交資料

一般伺服器會對請求的IP進行記錄,如果單位時間裡訪問的次數達到一個閥值, 會認為該IP地址是爬蟲,會彈出驗證碼驗證或者直接對IP進行封禁。一個最簡單 的方法就是延遲每次提交的時間,直接用**time模組sleep(秒)** 函式休眠下。

7) 代理

對應限制ip訪問速度的情況我們可以使用延遲提交資料的做法, 但是有些是限制訪問次數的,同一個ip只能在一段時間裡訪問 多少次這樣,而且休眠這種方法效率也是挺低的。更好的方案是 使用代理,通過代理ip輪換去訪問目標網址。 用法示例如下:

# 使用ip代理
ip_query_url = "http://www.whatismyip.com.tw"

# 1.建立代理處理器,ProxyHandler引數是一個字典{型別:代理ip:埠}
proxy_support = urllib.request.ProxyHandler({'http': '221.214.110.130:8080'})
# 2.定製,建立一個opener
opener = urllib.request.build_opener(proxy_support)
# 3.安裝opener
urllib.request.install_opener(opener)

headers = {
    'User-Agent': 'User-Agent:Mozilla/5.0 (X11; Linux x86_64)'
                  ' AppleWebKit/537.36 (KHTML, like Gecko)'
                  ' Chrome/63.0.3239.84 Safari/537.36',
    'Host': 'www.whatismyip.com.tw'
}
MAX_NUM = 10    # 有時網路堵塞,會報URLError錯誤,所以加一個迴圈
request = urllib.request.Request(ip_query_url, headers=headers)
for i in range(MAX_NUM):
    try:
        response = urllib.request.urlopen(request, timeout=20)
        html = response.read()
        print(html.decode('utf-8'))
        break
    except:
        if i < MAX_NUM - 1:
            continue
        else:
            print("urllib.error.URLError: <urlopen error timed out>")
複製程式碼

輸出結果

小豬的Python學習之旅 —— 2.爬蟲初涉

如圖代理成功,這裡的網站是用於查詢請求ip的,另外,我們一般會弄一個 代理ip的列表,然後每次隨機的從裡面取出一個來使用。

8) Cookie

Cookie定義:指某些網站為了辨別使用者身份、進行 session 跟蹤而儲存在使用者本地終端上的資料(通常經過加密) 比如有些頁面你在登入前是無法訪問的,你登入成功會給你分配 Cookie,然後你帶著Cookie去請求頁面才能正常訪問。 使用http.cookiejar這個模組可以幫我們獲取Cookie,實現模擬登入。 該模組的主要物件(父類->子類): CookieJar –> FileCookieJar –>MozillaCookieJar與LWPCookieJar

因為暫時沒找到合適例子,就只記下關鍵程式碼,後續有再改下例子:

# ============ 獲得Cookie ============

# 1.例項化CookieJar物件
cookie = cookiejar.CookieJar()

# 2.建立Cookie處理器
handler = urllib.request.HTTPCookieProcessor(cookie)

# 3.通過CookieHandler建立opener
opener = urllib.request.build_opener(handler)

# 4.開啟網頁
resp = opener.open("http://www.zhbit.com")

for i in cookie:
    print("Name = %s" % i.name)
    print("Name = %s" % i.value)
    
# ============ 儲存Cookie到檔案 ============
# 1.用於儲存cookie的檔案
cookie_file = "cookie.txt"

# 2.建立MozillaCookieJar物件儲存Cookie
cookie = cookiejar.MozillaCookieJar(cookie_file)

# 3.建立Cookie處理器
handler = urllib.request.HTTPCookieProcessor(cookie)

# 4.通過CookieHandler建立opener
opener = urllib.request.build_opener(handler)

# 5.開啟網頁
resp = opener.open("http://www.baidu.com")

# 6.儲存Cookie到檔案中,引數依次是:
# ignore_discard:即使cookies將被丟棄也將它儲存下來
# ignore_expires:如果在該檔案中cookies已存在,覆蓋原檔案寫入
cookie.save(ignore_discard=True, ignore_expires=True)

# ============ 讀取Cookie檔案 ============

cookie_file = "cookie.txt"

# 1.建立MozillaCookieJar物件儲存Cookie
cookie = cookiejar.MozillaCookieJar(cookie_file)

# 2.從檔案中讀取cookie內容
cookie.load(cookie_file, ignore_expires=True, ignore_discard=True)

handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
resp = opener.open("http://www.baidu.com")
print(resp.read().decode('utf-8'))

複製程式碼

9) URL編解碼

對於url有時我們需要進行編解碼,比如帶有中文的url,可以呼叫:

urllib.request.quote(xxx) # 編碼
urllib.request.unquote(xxx) # 解碼
複製程式碼

2.Beautiful Soup 庫詳解

1) 官方介紹

一個可以從 HTMLXML 檔案中提取資料的 Python庫,它能夠通過 你喜歡的轉換器實現慣用的文件導航、查詢、修改文件的方式。 Beautiful Soup 會幫你節省數小時甚至數天的工作時間。

簡單點說就是 爬取HTML和XML的利器

2) 安裝庫

PyCharm直接安裝File -> Default Settings -> Project Interpreter 選擇Python 3的版本 -> 點+號 -> 搜尋beautifulsoup4 安裝即可

pip方法安裝的自己行百度,或者看上一節的內容~

3) 例項化BeautifulSoup物件

簡單點說這一步就是把html丟到BeautifulSoup物件裡,可以是請求後的網站, 也可以是本地的HTML檔案,第二個引數是指定解析器,html.parser是內建的 html解析器,你還可以用lxml.parser,不過要另外導庫。

網站:soup = BeautifulSoup(resp.read(), 'html.parser') 本地:soup = BeautifulSoup(open('index.html'),'html.parser')

另外還可以呼叫**soup.prettify()**格式化輸出HTML

4) 四大物件

一.Tag(標籤)

查詢的是:在所有內容中第一個符合要求的標籤,最常用的兩個東東: tag.name:獲得tag的名字,比如body tag.attrs:獲取標籤內所有屬性,返回一個字典,可以根據鍵取值,也可以 直接呼叫get('xxx')拿到屬性。

還有個玩法是:可以soup.body.div.div.a 這樣玩,同過加標籤名的形式 輕鬆獲取標籤的內容,不過查詢的只是第一個!基本沒什麼卵用...

二.NavigableString(內部文字)

獲取標籤內部的文字,直接呼叫**.string**

三.BeautifulSoup(文件的全部內容)

當做一個Tag物件就好,只是可以分別獲取它的型別,名稱,一級屬性而已

四.Comment(特殊的NavigableString)

這種物件呼叫**.string來輸出內容會把註釋符號去掉**,直接把註釋裡的內容 打出來,需要加一波判斷:

if type(soup.a.string)==bs4.element.Comment:
    print soup.a.string  
複製程式碼

5) 各種節點

PS:就是找到了目標節點附近的節點,然後順藤摸瓜找到目標節點。

子節點與子孫節點contents:把標籤下的所有子標籤存入到列表,返回列表 children:和contents一樣,但是返回的不是一個列表而是 一個迭代器,只能通過迴圈的方式獲取資訊,型別是:list_iterator 前兩者僅包含tag的直接子節點,如果是想扒出子孫節點,可以使用descendants 會把所有節點都剝離出來,生成一個生成器物件<class 'generator'>

父節點與祖先節點 parent:返回父節點Tag parents:返回祖先節點,返回一個生成器物件

兄弟結點: 處於同一層級的結點,next_sibling下一個,previous_sibling 上一個,結點不存在返回None 所有兄弟節點next_siblingsprevious_sibling,返回一個生成器物件

前後結點next_elementprevious_element 所有前後結點next_elementsprevious_elements 返回一個生成器物件

6) 文件樹搜尋

最常用的方法

  • **find_all (self, name=None, attrs={}, recursive=True, text=None, limit=None, kwargs):

  • name引數:通過html標籤名直接搜尋,會自動忽略字串物件, 引數可以是:字串,正規表示式,列表,True或者自定義方法

  • keyword引數:通過html標籤的id,href(a標籤)和title,class要寫成class_, 可以同時過濾多個,對於不能用的tags屬性,可以直接用一個attrs字典包著, 比如:find_all(attrs={'data-foo': 'value'}

  • text:搜尋文件中的字串內容

  • limit:限制返回的結果數量

  • recursive:是否遞迴檢索所有子孫節點

其他方法

  • **find (self, name=None, attrs={}, recursive=True, text=None, kwargs): 和find_all作用一樣,只是返回的不是列表,而是直接返回結果。
  • find_parents()find_parent(): find_all() 和 find() 只搜尋當前節點的所有子節點,孫子節點等. find_parents() 和 find_parent()用來搜尋當前節點的父輩節點, 搜尋方法與普通tag的搜尋方法相同,搜尋文件搜尋文件包含的內容。
  • find_next_sibling()find_next_siblings(): 這2個方法通過 .next_siblings 屬性對當 tag 的所有後面解析的兄弟 tag 節點進行迭代, find_next_siblings() 方法返回所有符合條件的後面 的兄弟節點,find_next_sibling() 只返回符合條件的後面的第一個tag節點。
  • find_previous_siblings()find_previous_sibling(): 這2個方法通過 .previous_siblings 屬性對當前 tag 的前面解析的兄弟 tag 節點進行迭代, find_previous_siblings()方法返回所有符合條件的前面的 兄弟節點, find_previous_sibling() 方法返回第一個符合條件的前面的兄弟節點。
  • find_all_next()find_next(): 這2個方法通過 .next_elements 屬性對當前 tag 的之後的 tag 和字串進行 迭代, find_all_next() 方法返回所有符合條件的節點, find_next() 方法返回 第一個符合條件的節點。
  • find_all_previous()find_previous() 這2個方法通過 .previous_elements 屬性對當前節點前面的 tag 和字串 進行迭代, find_all_previous() 方法返回所有符合條件的節點, find_previous()方法返回第一個符合條件的節點

3.爬蟲實戰

1) 小說網站資料抓取下載txt到本地

上一節學習了基礎知識,這節又學了簡單的爬蟲姿勢:urllib和Beautiful Soup庫, 肯定是要來個實戰練練手的,選了個最簡單的而且有點卵用的小東西玩玩。 相信各位大佬平時都有看網路小說的習慣吧,應該很少有老司機去會起點 付費看,一般都有些盜版小說網站,比如:筆趣看:www.biqukan.com/ 手機線上看,廣告是可怕的,想想你在擠滿人的地跌上,突然蹦出一對 柰子,你的第一反應肯定是關掉,然而還是naive,點X直接彈一個新的 網頁什麼壯陽延時...尷尬得一匹。學了Python爬蟲的東西了,寫個小爬蟲 爬爬小說順道練練手豈不美滋滋。不說那麼多,開搞: 我最近在看的小說:唐家三少的《斗羅大陸3-龍王傳說》 www.biqukan.com/1_1496/

小豬的Python學習之旅 —— 2.爬蟲初涉

圖中圈住的部分就是小說的章節,F12開啟chrome的開發者工具,切到Network選項卡 (或者直接看Elements也行),選Response,重新整理一波可以看到這樣的HTML結構:

小豬的Python學習之旅 —— 2.爬蟲初涉

當然我們要找的內容不在這裡,繼續往下翻:

小豬的Python學習之旅 —— 2.爬蟲初涉

listmain這個全域性搜了下,是唯一的(好吧,找這個真的太沒難度了...) 直接find_all(attrs={'class': 'listmain'}) 就可以拿到這段東西了 find_all返回一個bs4.element.ResultSet 物件,for迴圈遍歷一波 這個物件,(迭代物件的型別是**:bs4.element.Tag**)列印一波可以看到:

小豬的Python學習之旅 —— 2.爬蟲初涉

我們要留下的只是<a>xxx</a>這種東西,可以在迴圈的時候順帶把 無關的篩選掉:

小豬的Python學習之旅 —— 2.爬蟲初涉

可以列印下這個a_list,剩下的全是<a>xxx</a>

小豬的Python學習之旅 —— 2.爬蟲初涉

因為最新章節列表那裡預設有12個,我們應該從楔子那裡開始, 所以把把a_list列表分下片:result_list = a_list[12:] 過濾掉前面的最新章節部分~

小豬的Python學習之旅 —— 2.爬蟲初涉

章節部分的資料就處理完畢了,有章節內容的url,以及章節的名稱, 接著我們來看看章節頁面的內容結構,隨便開啟一個: 比如:www.biqukan.com/1_1496/4503…

小豬的Python學習之旅 —— 2.爬蟲初涉

就不說了,class="showtxt"又是唯一的,直接: showtxt = chapter_soup.find_all(attrs={'class': 'showtxt'}) 把showtxt迴圈列印一波,裡面的東西就是我們想要的東東了~

小豬的Python學習之旅 —— 2.爬蟲初涉

url有了,章節名有了,內容有了,是時候寫入到檔案裡了,這個 過於簡單就不用多說了,strip=True代表刪除字元前後的所有空格:

小豬的Python學習之旅 —— 2.爬蟲初涉

到此我們爬區小說的小爬蟲就寫完了,不過有個小問題是,批量 快速訪問的時候,會報503異常,因為伺服器一般會對限制ip在 一段時間裡訪問的頻次,上面也講了要麼休眠,要麼搞ip代理, 肯定是搞ip代理嗨一些,接著我們來寫一個爬蟲來抓取西刺 代理的ip,並校驗是否可用,然後存到本地,我們的代理ip池, 哈哈~

小豬的Python學習之旅 —— 2.爬蟲初涉

附上小說抓取這部分的程式碼:

from bs4 import BeautifulSoup
import urllib.request
from urllib import error

novel_url = "http://www.biqukan.com/1_1496/"  # 小說頁面地址
base_url = "http://www.biqukan.com"  # 根地址,用於拼接

save_dir = "Novel/"  # 下載小說的存放路徑


# 儲存小說到本地
def save_chapter(txt, path):
    try:
        with open(path, "a+") as f:
            f.write(txt.get_text(strip=True))
    except (error.HTTPError, OSError) as reason:
        print(str(reason))
    else:
        print("下載完成:" + path)


# 獲得所有章節的url
def get_chapter_url():
    chapter_req = urllib.request.Request(novel_url)
    chapter_resp = urllib.request.urlopen(chapter_req, timeout=20)
    chapter_content = chapter_resp.read()
    chapter_soup = BeautifulSoup(chapter_content, 'html.parser')
    # 取出章節部分
    listmain = chapter_soup.find_all(attrs={'class': 'listmain'})
    a_list = []  # 存放小說所有的a標籤
    # 過濾掉不是a標籤的資料
    for i in listmain:
        if 'a' not in str(i):
            continue
        for d in i.findAll('a'):
            a_list.append(d)
    # 過濾掉前面"最新章節列表"部分
    result_list = a_list[12:]
    return result_list
    

# 獲取章節內容並下載
def get_chapter_content(c):
    chapter_url = base_url + c.attrs.get('href')  # 獲取url
    chapter_name = c.string  # 獲取章節名稱
    chapter_req = urllib.request.Request(chapter_url)
    chapter_resp = urllib.request.urlopen(chapter_req, timeout=20)
    chapter_content = chapter_resp.read()
    chapter_soup = BeautifulSoup(chapter_content, 'html.parser')
    # 查詢章節部分內容
    showtxt = chapter_soup.find_all(attrs={'class': 'showtxt'})
    for txt in showtxt:
        save_chapter(txt, save_dir + chapter_name + ".txt")


if __name__ == '__main__':
    novel_list = get_chapter_url()
    for chapter in novel_list:
        get_chapter_content(chapter)


複製程式碼

2) 抓取西刺代理ip並校驗是否可用

之前就說過了,很多伺服器都會限制ip訪問的頻度或者次數,可以通過設定代理 ip的方式來解決這個問題,代理ip百度一搜一堆,最出名的應該是西刺代理了: www.xicidaili.com/

小豬的Python學習之旅 —— 2.爬蟲初涉

爬蟲中代理ip使用得非常頻繁,每次都開啟這個頁面貼上複製,感覺 過於低端,而且還有個問題,代理ip是會過期失效的,而且不一定 一直可以用:要不來個這樣的騷操作:

寫個爬蟲爬取代理ip列表,然後校驗是否可用,把可用的存在本地, 下次需要代理的時候,讀取這個檔案中的ip,放到一個列表中,然後 輪流切換ip或者通過random模組隨機取出一個,去訪問目標地址。

抓取的網頁是:www.xicidaili.com/nn/1

小豬的Python學習之旅 —— 2.爬蟲初涉

Network選項卡,Response看下頁面結構,這裡我喜歡在PyCharm上 新建一個HTML檔案,結點可摺疊,找關鍵位置程式碼很方便:

小豬的Python學習之旅 —— 2.爬蟲初涉

如圖,不難發現就是我們要找的內容,可以從 find_all(attrs={'id': 'ip_list'}) 這裡入手,或者find_all('tr'),這裡有個小細節的地方首項是類似於表頭 的東西,我們可以通過列表分片去掉第一個:find_all('tr')[1:] 此時的列表:

小豬的Python學習之旅 —— 2.爬蟲初涉

接著就是要拿出ip和埠了,遍歷,先拿td,然後根據遊標拿資料:

小豬的Python學習之旅 —— 2.爬蟲初涉

資料都拼接成"ip:埠號"的形式了,然後就是驗證這個列表裡的代理 是否都可以用了,驗證方法也很簡單,直接設定代理然後訪問百度, 淘寶之類的網站,看返回碼是否為200,是的話就代表代理可用,追加 到可用列表中,最後再把可用列表寫入到檔案中:

小豬的Python學習之旅 —— 2.爬蟲初涉

然後你就有自己的代理ip池了,要用的時候讀取下檔案就好,沒事更新一波檔案~ 有了代理ip池,和上面扒小說的程式可用結合一波,應該就不會出現503的問題了, 具體有興趣的自行去完善吧(我懶...)

附上完整程式碼:

from bs4 import BeautifulSoup
import urllib.request
from urllib import error

test_url = "https://www.baidu.com/"  # 測試ip是否可用
proxy_url = "http://www.xicidaili.com/nn/1"  # ip抓取源
ip_file = "availableIP.txt"


# 把ip寫入到檔案中
def write_file(available_list):
    try:
        with open(ip_file, "w+") as f:
            for available_ip in available_list:
                f.write(available_ip + "\n")
    except OSError as reason:
        print(str(reason))


# 檢測代理ip是否可用,返回可用代理ip列表
def test_ip(test_list):
    available_ip_list = []
    for test in test_list:
        proxy = {'http': test}
        try:
            handler = urllib.request.ProxyHandler(proxy)
            opener = urllib.request.build_opener(handler)
            urllib.request.install_opener(opener)
            test_resp = urllib.request.urlopen(test_url)
            if test_resp.getcode() == 200:
                available_ip_list.append(test)
        except error.HTTPError as reason:
            print(str(reason))
    return available_ip_list


# 抓取西刺代理ip
def catch_ip():
    ip_list = []
    try:
        # 要設定請求頭,不然503
        headers = {
            'Host': 'www.xicidaili.com',
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
                          ' (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
        }
        req = urllib.request.Request(proxy_url, headers=headers)
        resp = urllib.request.urlopen(req, timeout=20)
        content = resp.read()
        soup = BeautifulSoup(content, 'html.parser')
        catch_list = soup.find_all('tr')[1:]

        # 儲存代理ip
        for i in catch_list:
            td = i.find_all('td')
            ip_list.append(td[1].get_text() + ":" + td[2].get_text())

        return ip_list
    except urllib.error.URLError as reason:
        print(str(reason))


if __name__ == "__main__":
    xici_ip_list = catch_ip()
    available_ip_list = test_ip(xici_ip_list)
    write_file(available_ip_list)

複製程式碼

結語

本節學習了urllib庫與Beautiful Soup,並通過兩個非常簡單的程式體驗了 一波爬蟲的編寫,順道溫習了下上節的基礎知識,美滋滋,比起Android 天天寫介面,有趣太多,本節的東西還是小兒科,下節我們來啃硬骨頭 正規表示式!敬請期待~

小豬的Python學習之旅 —— 2.爬蟲初涉


本節參考文獻


來啊,Py交易啊

想加群一起學習Py的可以加下,智障機器人小Pig,驗證資訊裡包含: PythonpythonpyPy加群交易屁眼 中的一個關鍵詞即可通過;

小豬的Python學習之旅 —— 2.爬蟲初涉

驗證通過後回覆 加群 即可獲得加群連結(不要把機器人玩壞了!!!)~~~ 歡迎各種像我一樣的Py初學者,Py大神加入,一起愉快地交流學♂習,van♂轉py。

小豬的Python學習之旅 —— 2.爬蟲初涉


相關文章