久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

小豬的Python學(xué)習(xí)之旅

 大傻子的文淵閣 2019-12-30

小豬的Python學(xué)習(xí)之旅 —— 2.爬蟲初涉



引言

本節(jié)開始學(xué)習(xí)Python爬蟲,,先是介紹兩個(gè)玩到爛的兩個(gè)庫(kù)urllib和BeautifulSoup,,
然后寫了兩個(gè)很簡(jiǎn)單的小爬蟲來(lái)體驗(yàn)下爬蟲的魅力,建議直接把代碼復(fù)制粘貼一波
體驗(yàn)下,覺(jué)得有點(diǎn)意思再一點(diǎn)點(diǎn)學(xué)習(xí)~學(xué)什么東西興趣很重要,!


1.urllib模塊詳解

用于操作URL的模塊(庫(kù),,py3把urllib和urllib2合并到了一起)
爬網(wǎng)頁(yè)必須掌握的最基礎(chǔ)的東東。

1) 爬取網(wǎng)頁(yè)

import urllib.request
import urllib.parse
import json

# 爬取網(wǎng)頁(yè)信息
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() # 獲得頭相關(guān)的信息,HTTPMessage對(duì)象
html_resp.getcode() # 獲得狀態(tài)碼
html_resp.geturl() # 獲取爬取的url

# url中包含漢字是不符合URL標(biāo)準(zhǔn)的,,需要進(jìn)行編碼
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) 爬取二進(jìn)制文件(圖片,,音頻等)

# 下載圖片
pic_url = "http://static./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)

# 也可以直接調(diào)用urlretrieve下載,比如下載音頻
music_url = "http://7xl4pr.com2.z0.glb./"             "%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請(qǐng)求與Post請(qǐng)求

PS:下面用到的json模塊:用于將Python原始類型與json類型相互轉(zhuǎn)換,使用
如果是讀取文件可以用:dump()和load()方法,,字符串的話用下述兩個(gè):

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:///api/data/" + urllib.request.quote("福利") + "/1/1"
get_resp = urllib.request.urlopen(get_url)
get_result = json.loads(get_resp.read().decode('utf-8'))
# 這里后面的參數(shù)用于格式化Json輸出格式
get_result_format = json.dumps(get_result, indent=2,
                               sort_keys=True,  ensure_ascii=False)
print(get_result_format)

# 模擬Post
post_url = "http://.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結(jié)果轉(zhuǎn)Json
print(json.dumps(result, sort_keys=True, 
                 indent=2, ensure_ascii=False)) # 格式化輸出Json

4) 修改請(qǐng)求頭

有些網(wǎng)站為了避免別人使用爬蟲惡意采取信息會(huì)進(jìn)行一些反爬蟲的操作,,
比如通過(guò)請(qǐng)求頭里的User-Agent,檢查訪問(wèn)來(lái)源是否為正常的訪問(wèn)途徑,,
我們可以修改請(qǐng)求頭來(lái)進(jìn)行模擬正常的訪問(wèn),。Request中有個(gè)headers參數(shù),
有兩種方法進(jìn)行設(shè)置:
1.把請(qǐng)求頭都塞到字典里,,實(shí)例化Request對(duì)象的時(shí)候傳入
2.通過(guò)Request對(duì)象的add_header()方法一個(gè)個(gè)添加

# 修改頭信息
novel_url = "http://www./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) 設(shè)置連接超時(shí)

# urlopen函數(shù)時(shí)添加timeout參數(shù),,單位是秒
urllib.request.urlopen(novel_req, timeout=20)

6) 延遲提交數(shù)據(jù)

一般服務(wù)器會(huì)對(duì)請(qǐng)求的IP進(jìn)行記錄,如果單位時(shí)間里訪問(wèn)的次數(shù)達(dá)到一個(gè)閥值,,
會(huì)認(rèn)為該IP地址是爬蟲,,會(huì)彈出驗(yàn)證碼驗(yàn)證或者直接對(duì)IP進(jìn)行封禁。一個(gè)最簡(jiǎn)單
的方法就是延遲每次提交的時(shí)間,,直接用time模塊sleep(秒) 函數(shù)休眠下,。

7) 代理

對(duì)應(yīng)限制ip訪問(wèn)速度的情況我們可以使用延遲提交數(shù)據(jù)的做法,
但是有些是限制訪問(wèn)次數(shù)的,,同一個(gè)ip只能在一段時(shí)間里訪問(wèn)
多少次這樣,,而且休眠這種方法效率也是挺低的。更好的方案是
使用代理,,通過(guò)代理ip輪換去訪問(wèn)目標(biāo)網(wǎng)址,。 用法示例如下:

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

# 1.創(chuàng)建代理處理器,ProxyHandler參數(shù)是一個(gè)字典{類型:代理ip:端口}
proxy_support = urllib.request.ProxyHandler({'http': '221.214.110.130:8080'})
# 2.定制,,創(chuàng)建一個(gè)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.'
}
MAX_NUM = 10    # 有時(shí)網(wǎng)絡(luò)堵塞,,會(huì)報(bào)URLError錯(cuò)誤,所以加一個(gè)循環(huán)
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>")

輸出結(jié)果

如圖代理成功,,這里的網(wǎng)站是用于查詢請(qǐng)求ip的,,另外,我們一般會(huì)弄一個(gè)
代理ip的列表,,然后每次隨機(jī)的從里面取出一個(gè)來(lái)使用。

8) Cookie

Cookie定義:指某些網(wǎng)站為了辨別用戶身份、進(jìn)行 session
跟蹤而儲(chǔ)存在用戶本地終端上的數(shù)據(jù)(通常經(jīng)過(guò)加密)
比如有些頁(yè)面你在登錄前是無(wú)法訪問(wèn)的,,你登錄成功會(huì)給你分配
Cookie,,然后你帶著Cookie去請(qǐng)求頁(yè)面才能正常訪問(wèn)。
使用http.cookiejar這個(gè)模塊可以幫我們獲取Cookie,,實(shí)現(xiàn)模擬登錄,。
該模塊的主要對(duì)象(父類->子類):
CookieJar –> FileCookieJar –>MozillaCookieJar與LWPCookieJar

因?yàn)闀簳r(shí)沒(méi)找到合適例子,就只記下關(guān)鍵代碼,,后續(xù)有再改下例子:

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

# 1.實(shí)例化CookieJar對(duì)象
cookie = cookiejar.CookieJar()

# 2.創(chuàng)建Cookie處理器
handler = urllib.request.HTTPCookieProcessor(cookie)

# 3.通過(guò)CookieHandler創(chuàng)建opener
opener = urllib.request.build_opener(handler)

# 4.打開網(wǎng)頁(yè)
resp = opener.open("http://www.")

for i in cookie:
    print("Name = %s" % i.name)
    print("Name = %s" % i.value)

# ============ 保存Cookie到文件 ============
# 1.用于保存cookie的文件
cookie_file = "cookie.txt"

# 2.創(chuàng)建MozillaCookieJar對(duì)象保存Cookie
cookie = cookiejar.MozillaCookieJar(cookie_file)

# 3.創(chuàng)建Cookie處理器
handler = urllib.request.HTTPCookieProcessor(cookie)

# 4.通過(guò)CookieHandler創(chuàng)建opener
opener = urllib.request.build_opener(handler)

# 5.打開網(wǎng)頁(yè)
resp = opener.open("http://www.baidu.com")

# 6.保存Cookie到文件中,,參數(shù)依次是:
# ignore_discard:即使cookies將被丟棄也將它保存下來(lái)
# ignore_expires:如果在該文件中cookies已存在,覆蓋原文件寫入
cookie.save(ignore_discard=True, ignore_expires=True)

# ============ 讀取Cookie文件 ============

cookie_file = "cookie.txt"

# 1.創(chuàng)建MozillaCookieJar對(duì)象保存Cookie
cookie = cookiejar.MozillaCookieJar(cookie_file)

# 2.從文件中讀取cookie內(nèi)容
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'))

2.Beautiful Soup 庫(kù)詳解

1) 官方介紹

一個(gè)可以從 HTMLXML 文件中提取數(shù)據(jù)的 Python庫(kù),,它能夠通過(guò)
你喜歡的轉(zhuǎn)換器實(shí)現(xiàn)慣用的文檔導(dǎo)航,、查找、修改文檔的方式,。
Beautiful Soup 會(huì)幫你節(jié)省數(shù)小時(shí)甚至數(shù)天的工作時(shí)間,。

簡(jiǎn)單點(diǎn)說(shuō)就是 爬取HTML和XML的利器

2) 安裝庫(kù)

PyCharm直接安裝
File -> Default Settings -> Project Interpreter 選擇Python 3的版本
-> 點(diǎn)+號(hào) -> 搜索beautifulsoup4 安裝即可

pip方法安裝的自己行百度,或者看上一節(jié)的內(nèi)容~

3) 實(shí)例化BeautifulSoup對(duì)象

簡(jiǎn)單點(diǎn)說(shuō)這一步就是把html丟到BeautifulSoup對(duì)象里,,可以是請(qǐng)求后的網(wǎng)站,,
也可以是本地的HTML文件,第二個(gè)參數(shù)是指定解析器,,html.parser是內(nèi)置的
html解析器,,你還可以用lxml.parser,不過(guò)要另外導(dǎo)庫(kù),。

網(wǎng)站:soup = BeautifulSoup(resp.read(), ‘html.parser’)
本地:soup = BeautifulSoup(open(‘index.html’),,’html.parser’)

另外還可以調(diào)用soup.prettify()格式化輸出HTML

4) 四大對(duì)象

一.Tag(標(biāo)簽)

查找的是:在所有內(nèi)容中第一個(gè)符合要求的標(biāo)簽,最常用的兩個(gè)東東:
tag.name:獲得tag的名字,,比如body
tag.attrs:獲取標(biāo)簽內(nèi)所有屬性,,返回一個(gè)字典,可以根據(jù)鍵取值,,也可以
直接調(diào)用get(‘xxx’)拿到屬性,。

還有個(gè)玩法是:可以soup.body.div.div.a 這樣玩,同過(guò)加標(biāo)簽名的形式
輕松獲取標(biāo)簽的內(nèi)容,,不過(guò)查找的只是第一個(gè),!基本沒(méi)什么卵用…

二.NavigableString(內(nèi)部文字)

獲取標(biāo)簽內(nèi)部的文字,直接調(diào)用.string

三.BeautifulSoup(文檔的全部?jī)?nèi)容)

當(dāng)做一個(gè)Tag對(duì)象就好,,只是可以分別獲取它的類型,,名稱,一級(jí)屬性而已

四.Comment(特殊的NavigableString)

這種對(duì)象調(diào)用.string來(lái)輸出內(nèi)容會(huì)把注釋符號(hào)去掉,,直接把注釋里的內(nèi)容
打出來(lái),,需要加一波判斷:

if type(soup.a.string)==bs4.element.Comment:
    print soup.a.string  

5) 各種節(jié)點(diǎn)

PS:感覺(jué)作用不大,,用得不多,還是記錄下方法,,可以跳過(guò)~

子節(jié)點(diǎn)與子孫節(jié)點(diǎn)
contents:把標(biāo)簽下的所有子標(biāo)簽存入到列表,,返回列表
children:和contents一樣,但是返回的不是一個(gè)列表而是
一個(gè)迭代器,,只能通過(guò)循環(huán)的方式獲取信息,,類型是:list_iterator
前兩者僅包含tag的直接子節(jié)點(diǎn),如果是想扒出子孫節(jié)點(diǎn),,可以使用descendants
會(huì)把所有節(jié)點(diǎn)都剝離出來(lái),,生成一個(gè)生成器對(duì)象

6) 文檔樹搜索

最常用的方法

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

    • name參數(shù):通過(guò)html標(biāo)簽名直接搜索,會(huì)自動(dòng)忽略字符串對(duì)象,,
      參數(shù)可以是:字符串,,正則表達(dá)式,列表,,True或者自定義方法

    • keyword參數(shù):通過(guò)html標(biāo)簽的id,,href(a標(biāo)簽)和title,class要寫成class_,,
      可以同時(shí)過(guò)濾多個(gè),,對(duì)于不能用的tags屬性,可以直接用一個(gè)attrs字典包著,,
      比如:find_all(attrs={‘data-foo’: ‘value’}

    • text:搜索文檔中的字符串內(nèi)容

    • limit:限制返回的結(jié)果數(shù)量

    • recursive:是否遞歸檢索所有子孫節(jié)點(diǎn)

其他方法

  • find (self, name=None, attrs={}, recursive=True, text=None, **kwargs):
    和find_all作用一樣,,只是返回的不是列表,而是直接返回結(jié)果,。

  • find_parents()find_parent()
    find_all() 和 find() 只搜索當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn),孫子節(jié)點(diǎn)等.
    find_parents() 和 find_parent()用來(lái)搜索當(dāng)前節(jié)點(diǎn)的父輩節(jié)點(diǎn),
    搜索方法與普通tag的搜索方法相同,搜索文檔搜索文檔包含的內(nèi)容,。

  • find_next_sibling()find_next_siblings()
    這2個(gè)方法通過(guò) .next_siblings 屬性對(duì)當(dāng) tag 的所有后面解析的兄弟
    tag 節(jié)點(diǎn)進(jìn)行迭代, find_next_siblings() 方法返回所有符合條件的后面
    的兄弟節(jié)點(diǎn),find_next_sibling() 只返回符合條件的后面的第一個(gè)tag節(jié)點(diǎn)。

  • find_previous_siblings()find_previous_sibling()
    這2個(gè)方法通過(guò) .previous_siblings 屬性對(duì)當(dāng)前 tag 的前面解析的兄弟
    tag 節(jié)點(diǎn)進(jìn)行迭代, find_previous_siblings()方法返回所有符合條件的前面的
    兄弟節(jié)點(diǎn), find_previous_sibling() 方法返回第一個(gè)符合條件的前面的兄弟節(jié)點(diǎn),。

  • find_all_next()find_next()
    這2個(gè)方法通過(guò) .next_elements 屬性對(duì)當(dāng)前 tag 的之后的 tag 和字符串進(jìn)行
    迭代, find_all_next() 方法返回所有符合條件的節(jié)點(diǎn), find_next() 方法返回
    第一個(gè)符合條件的節(jié)點(diǎn),。

  • find_all_previous()find_previous()
    這2個(gè)方法通過(guò) .previous_elements 屬性對(duì)當(dāng)前節(jié)點(diǎn)前面的 tag 和字符串
    進(jìn)行迭代, find_all_previous() 方法返回所有符合條件的節(jié)點(diǎn),
    find_previous()方法返回第一個(gè)符合條件的節(jié)點(diǎn)


3.爬蟲實(shí)戰(zhàn)

1) 小說(shuō)網(wǎng)站數(shù)據(jù)抓取下載txt到本地

上一節(jié)學(xué)習(xí)了基礎(chǔ)知識(shí),這節(jié)又學(xué)了簡(jiǎn)單的爬蟲姿勢(shì):urllib和Beautiful Soup庫(kù),,
肯定是要來(lái)個(gè)實(shí)戰(zhàn)練練手的,,選了個(gè)最簡(jiǎn)單的而且有點(diǎn)卵用的小東西玩玩。
相信各位大佬平時(shí)都有看網(wǎng)絡(luò)小說(shuō)的習(xí)慣吧,,應(yīng)該很少有老司機(jī)去會(huì)起點(diǎn)
付費(fèi)看,,一般都有些盜版小說(shuō)網(wǎng)站,比如:筆趣看:http://www./
手機(jī)在線看,,廣告是可怕的,,想想你在擠滿人的地跌上,突然蹦出一對(duì)
柰子,,你的第一反應(yīng)肯定是關(guān)掉,,然而還是naive,,點(diǎn)X直接彈一個(gè)新的
網(wǎng)頁(yè)什么壯陽(yáng)延時(shí)…尷尬得一匹。學(xué)了Python爬蟲的東西了,,寫個(gè)小爬蟲
爬爬小說(shuō)順道練練手豈不美滋滋,。不說(shuō)那么多,開搞:
我最近在看的小說(shuō):唐家三少的《斗羅大陸3-龍王傳說(shuō)》
http://www./1_1496/

圖中圈住的部分就是小說(shuō)的章節(jié),,F(xiàn)12打開chrome的開發(fā)者工具,切到Network選項(xiàng)卡
(或者直接看Elements也行),,選Response,,刷新一波可以看到這樣的HTML結(jié)構(gòu):

當(dāng)然我們要找的內(nèi)容不在這里,繼續(xù)往下翻:

listmain這個(gè)全局搜了下,,是唯一的(好吧,,找這個(gè)真的太沒(méi)難度了…)
直接find_all(attrs={‘class’: ‘listmain’}) 就可以拿到這段東西了
find_all返回一個(gè)bs4.element.ResultSet 對(duì)象,for循環(huán)遍歷一波
這個(gè)對(duì)象,,(迭代對(duì)象的類型是:bs4.element.Tag)打印一波可以看到:

我們要留下的只是<a>xxx</a>這種東西,,可以在循環(huán)的時(shí)候順帶把
無(wú)關(guān)的篩選掉:

可以打印下這個(gè)a_list,剩下的全是<a>xxx</a>

因?yàn)樽钚抡鹿?jié)列表那里默認(rèn)有12個(gè),,我們應(yīng)該從楔子那里開始,,
所以把把a(bǔ)_list列表分下片:result_list = a_list[12:]
過(guò)濾掉前面的最新章節(jié)部分~

章節(jié)部分的數(shù)據(jù)就處理完畢了,有章節(jié)內(nèi)容的url,,以及章節(jié)的名稱,,
接著我們來(lái)看看章節(jié)頁(yè)面的內(nèi)容結(jié)構(gòu),隨便打開一個(gè):
比如:http://www./1_1496/450364.html

就不說(shuō)了,,class=”showtxt”又是唯一的,,直接:
showtxt = chapter_soup.find_all(attrs={‘class’: ‘showtxt’})
把showtxt循環(huán)打印一波,里面的東西就是我們想要的東東了~

url有了,,章節(jié)名有了,,內(nèi)容有了,是時(shí)候?qū)懭氲轿募锪?,這個(gè)
過(guò)于簡(jiǎn)單就不用多說(shuō)了,,strip=True代表刪除字符前后的所有空格:

到此我們爬區(qū)小說(shuō)的小爬蟲就寫完了,不過(guò)有個(gè)小問(wèn)題是,,批量
快速訪問(wèn)的時(shí)候,,會(huì)報(bào)503異常,因?yàn)榉?wù)器一般會(huì)對(duì)限制ip在
一段時(shí)間里訪問(wèn)的頻次,,上面也講了要么休眠,,要么搞ip代理,
肯定是搞ip代理嗨一些,,接著我們來(lái)寫一個(gè)爬蟲來(lái)抓取西刺
代理的ip,,并校驗(yàn)是否可用,,然后存到本地,我們的代理ip池,,
哈哈~

附上小說(shuō)抓取這部分的代碼:

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

novel_url = "http://www./1_1496/"  # 小說(shuō)頁(yè)面地址
base_url = "http://www."  # 根地址,,用于拼接

save_dir = "Novel/"  # 下載小說(shuō)的存放路徑


# 保存小說(shuō)到本地
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)


# 獲得所有章節(jié)的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')
    # 取出章節(jié)部分
    listmain = chapter_soup.find_all(attrs={'class': 'listmain'})
    a_list = []  # 存放小說(shuō)所有的a標(biāo)簽
    # 過(guò)濾掉不是a標(biāo)簽的數(shù)據(jù)
    for i in listmain:
        if 'a' not in str(i):
            continue
        for d in i.findAll('a'):
            a_list.append(d)
    # 過(guò)濾掉前面"最新章節(jié)列表"部分
    result_list = a_list[12:]
    return result_list


# 獲取章節(jié)內(nèi)容并下載
def get_chapter_content(c):
    chapter_url = base_url + c.attrs.get('href')  # 獲取url
    chapter_name = c.string  # 獲取章節(jié)名稱
    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')
    # 查找章節(jié)部分內(nèi)容
    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并校驗(yàn)是否可用

之前就說(shuō)過(guò)了,很多服務(wù)器都會(huì)限制ip訪問(wèn)的頻度或者次數(shù),,可以通過(guò)設(shè)置代理
ip的方式來(lái)解決這個(gè)問(wèn)題,,代理ip百度一搜一堆,最出名的應(yīng)該是西刺代理了:
http://www./

爬蟲中代理ip使用得非常頻繁,,每次都打開這個(gè)頁(yè)面粘貼復(fù)制,,感覺(jué)
過(guò)于低端,而且還有個(gè)問(wèn)題,,代理ip是會(huì)過(guò)期失效的,,而且不一定
一直可以用:要不來(lái)個(gè)這樣的騷操作:

寫個(gè)爬蟲爬取代理ip列表,然后校驗(yàn)是否可用,,把可用的存在本地,,
下次需要代理的時(shí)候,讀取這個(gè)文件中的ip,,放到一個(gè)列表中,,然后
輪流切換ip或者通過(guò)random模塊隨機(jī)取出一個(gè),去訪問(wèn)目標(biāo)地址,。

抓取的網(wǎng)頁(yè)是:http://www./nn/1

Network選項(xiàng)卡,,Response看下頁(yè)面結(jié)構(gòu),這里我喜歡在PyCharm上
新建一個(gè)HTML文件,,結(jié)點(diǎn)可折疊,,找關(guān)鍵位置代碼很方便:

如圖,不難發(fā)現(xiàn)就是我們要找的內(nèi)容,,可以從 find_all(attrs={‘id’: ‘ip_list’})
這里入手,,或者find_all(‘tr’),這里有個(gè)小細(xì)節(jié)的地方首項(xiàng)是類似于表頭
的東西,,我們可以通過(guò)列表分片去掉第一個(gè):find_all(‘tr’)[1:]
此時(shí)的列表:

接著就是要拿出ip和端口了,,遍歷,先拿td,,然后根據(jù)游標(biāo)拿數(shù)據(jù):

數(shù)據(jù)都拼接成”ip:端口號(hào)”的形式了,,然后就是驗(yàn)證這個(gè)列表里的代理
是否都可以用了,驗(yàn)證方法也很簡(jiǎn)單,,直接設(shè)置代理然后訪問(wèn)百度,,
淘寶之類的網(wǎng)站,看返回碼是否為200,,是的話就代表代理可用,,追加
到可用列表中,,最后再把可用列表寫入到文件中:

然后你就有自己的代理ip池了,要用的時(shí)候讀取下文件就好,,沒(méi)事更新一波文件~
有了代理ip池,,和上面扒小說(shuō)的程序可用結(jié)合一波,應(yīng)該就不會(huì)出現(xiàn)503的問(wèn)題了,,
具體有興趣的自行去完善吧(我懶…)

附上完整代碼:

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

test_url = "https://www.baidu.com/"  # 測(cè)試ip是否可用
proxy_url = "http://www./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))


# 檢測(cè)代理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:
        # 要設(shè)置請(qǐng)求頭,不然503
        headers = {
            'Host': 'www.',
            '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)

結(jié)語(yǔ)

本節(jié)學(xué)習(xí)了urllib庫(kù)與Beautiful Soup,,并通過(guò)兩個(gè)非常簡(jiǎn)單的程序體驗(yàn)了
一波爬蟲的編寫,,順道溫習(xí)了下上節(jié)的基礎(chǔ)知識(shí),美滋滋,,比起Android
天天寫界面,有趣太多,,正如基神所言,,是時(shí)候找個(gè)新方向?qū)W習(xí)了~
本節(jié)的東西還是小兒科,下節(jié)我們來(lái)啃硬骨頭正則表達(dá)式,!


本節(jié)參考文獻(xiàn)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多