一、前言
強(qiáng)烈建議:請(qǐng)?jiān)陔娔X的陪同下,閱讀本文。本文以實(shí)戰(zhàn)為主,閱讀過(guò)程如稍有不適,還望多加練習(xí)。
本文的實(shí)戰(zhàn)內(nèi)容有:
網(wǎng)絡(luò)小說(shuō)下載(靜態(tài)網(wǎng)站)
優(yōu)美壁紙下載(動(dòng)態(tài)網(wǎng)站)
愛(ài)奇藝VIP視頻下載
二、網(wǎng)絡(luò)爬蟲(chóng)簡(jiǎn)介
網(wǎng)絡(luò)爬蟲(chóng),也叫網(wǎng)絡(luò)蜘蛛(Web Spider)。它根據(jù)網(wǎng)頁(yè)地址(URL)爬取網(wǎng)頁(yè)內(nèi)容,而網(wǎng)頁(yè)地址(URL)就是我們?cè)跒g覽器中輸入的網(wǎng)站鏈接。比如:https://www.baidu.com/,它就是一個(gè)URL。
在講解爬蟲(chóng)內(nèi)容之前,我們需要先學(xué)習(xí)一項(xiàng)寫(xiě)爬蟲(chóng)的必備技能:審查元素(如果已掌握,可跳過(guò)此部分內(nèi)容)。
1. 審查元素
在瀏覽器的地址欄輸入U(xiǎn)RL地址,在網(wǎng)頁(yè)處右鍵單擊,找到檢查,如下圖所示:(不同瀏覽器的叫法不同,Chrome瀏覽器叫做檢查,F(xiàn)irefox瀏覽器叫做查看元素,但是功能都是相同的)
我們可以看到,右側(cè)出現(xiàn)了一大推代碼,這些代碼就叫做HTML。什么是HTML?舉個(gè)容易理解的例子:我們的基因決定了我們的原始容貌,服務(wù)器返回的HTML決定了網(wǎng)站的原始容貌。
為啥說(shuō)是原始容貌呢?因?yàn)槿丝梢哉莅?!扎心了,有木有?那網(wǎng)站也可以"整容"嗎?可以!請(qǐng)看下圖:
我能有這么多錢(qián)嗎?顯然不可能。我是怎么給網(wǎng)站"整容"的呢?就是通過(guò)修改服務(wù)器返回的HTML信息。我們每個(gè)人都是"整容大師",可以修改頁(yè)面信息。我們?cè)陧?yè)面的哪個(gè)位置點(diǎn)擊審查元素,瀏覽器就會(huì)為我們定位到相應(yīng)的HTML位置,進(jìn)而就可以在本地更改HTML信息。
再舉個(gè)小例子:我們都知道,使用瀏覽器"記住密碼"的功能,密碼會(huì)變成一堆小黑點(diǎn),是不可見(jiàn)的。可以讓密碼顯示出來(lái)嗎?可以,只需給頁(yè)面"動(dòng)個(gè)小手術(shù)"!以淘寶為例,在輸入密碼框處右鍵,點(diǎn)擊檢查。
可以看到,瀏覽器為我們自動(dòng)定位到了相應(yīng)的HTML位置。將下圖中的password屬性值改為text屬性值(直接在右側(cè)代碼處修改):
就這樣,瀏覽器"記住的密碼"顯現(xiàn)出來(lái)了:
說(shuō)這么多,什么意思呢?瀏覽器就是作為客戶(hù)端從服務(wù)器端獲取信息,然后將信息解析,并展示給我們的。我們可以在本地修改HTML信息,為網(wǎng)頁(yè)"整容",但是我們修改的信息不會(huì)回傳到服務(wù)器,服務(wù)器存儲(chǔ)的HTML信息不會(huì)改變。刷新一下界面,頁(yè)面還會(huì)回到原本的樣子。這就跟人整容一樣,我們能改變一些表面的東西,但是不能改變我們的基因。
2. 簡(jiǎn)單實(shí)例
網(wǎng)絡(luò)爬蟲(chóng)的第一步就是根據(jù)URL,獲取網(wǎng)頁(yè)的HTML信息。在Python3中,可以使用urllib.request和requests進(jìn)行網(wǎng)頁(yè)爬取。
urllib庫(kù)是python內(nèi)置的,無(wú)需我們額外安裝,只要安裝了Python就可以使用這個(gè)庫(kù)。
requests庫(kù)是第三方庫(kù),需要我們自己安裝。
requests庫(kù)強(qiáng)大好用,所以本文使用requests庫(kù)獲取網(wǎng)頁(yè)的HTML信息。requests庫(kù)的github地址:https://github.com/requests/requests
(1)requests安裝
在學(xué)習(xí)使用requests庫(kù)之前,我們需要在電腦中安裝好requests庫(kù)。在cmd中,使用如下指令安裝requests庫(kù):
pip install requests
easy_install requests
# -*- coding:UTF-8 -*- import requests if __name__ == '__main__': target = 'http://gitbook.cn/' req = requests.get(url=target) print(req.text)
# -*- coding:UTF-8 -*-
import requests
if __name__ == '__main__':
target = 'http://www.biqukan.com/1_1094/5403177.html'
req = requests.get(url=target)
print(req.text)
pip install beautifulsoup4
easy_install beautifulsoup4
<div id="content", class="showtxt">
# -*- coding:UTF-8 -*- from bs4 import BeautifulSoup import requests if __name__ == "__main__": target = 'http://www.biqukan.com/1_1094/5403177.html' req = requests.get(url = target) html = req.text bf = BeautifulSoup(html) texts = bf.find_all('div', class_ = 'showtxt') print(texts)
<div id="content", class="showtxt">
# -*- coding:UTF-8 -*- from bs4 import BeautifulSoup import requests if __name__ == "__main__": target = 'http://www.biqukan.com/1_1094/5403177.html' req = requests.get(url = target) html = req.text bf = BeautifulSoup(html) texts = bf.find_all('div', class_ = 'showtxt') print(texts[0].text.replace('\xa0'*8,'\n\n'))
<div class="listmain"> <dl> <dt>《一念永恒》最新章節(jié)列表</dt> <dd><a href="/1_1094/15932394.html">第1027章 第十道門(mén)</a></dd> <dd><a href="/1_1094/15923072.html">第1026章 絕倫道法!</a></dd> <dd><a href="/1_1094/15921862.html">第1025章 長(zhǎng)生燈!</a></dd> <dd><a href="/1_1094/15918591.html">第1024章 一目晶淵</a></dd> <dd><a href="/1_1094/15906236.html">第1023章 通天道門(mén)</a></dd> <dd><a href="/1_1094/15903775.html">第1022章 四大兇獸!</a></dd> <dd><a href="/1_1094/15890427.html">第1021章 鱷首!</a></dd> <dd><a href="/1_1094/15886627.html">第1020章 一觸即發(fā)!</a></dd> <dd><a href="/1_1094/15875306.html">第1019章 魁祖的氣息!</a></dd> <dd><a href="/1_1094/15871572.html">第1018章 絕望的魁皇城</a></dd> <dd><a href="/1_1094/15859514.html">第1017章 我還是恨你!</a></dd> <dd><a href="/1_1094/15856137.html">第1016章 從來(lái)沒(méi)有世界之門(mén)!</a></dd> <dt>《一念永恒》正文卷</dt> <dd><a href="/1_1094/5386269.html">外傳1 柯父。</a></dd> <dd><a href="/1_1094/5386270.html">外傳2 楚玉嫣。</a></dd> <dd><a href="/1_1094/5386271.html">外傳3 鸚鵡與皮凍。</a></dd> <dd><a href="/1_1094/5403177.html">第一章 他叫白小純</a></dd> <dd><a href="/1_1094/5428081.html">第二章 火灶房</a></dd> <dd><a href="/1_1094/5433843.html">第三章 六句真言</a></dd> <dd><a href="/1_1094/5447905.html">第四章 煉靈</a></dd> </dl> </div>
http://www.biqukan.com/1_1094/5403177.html <a href="/1_1094/5403177.html">第一章 他叫白小純</a>
# -*- coding:UTF-8 -*- from bs4 import BeautifulSoup import requests if __name__ == "__main__": target = 'http://www.biqukan.com/1_1094/' req = requests.get(url = target) html = req.text div_bf = BeautifulSoup(html) div = div_bf.find_all('div', class_ = 'listmain') print(div[0])
# -*- coding:UTF-8 -*- from bs4 import BeautifulSoup import requests if __name__ == "__main__": server = 'http://www.biqukan.com/' target = 'http://www.biqukan.com/1_1094/' req = requests.get(url = target) html = req.text div_bf = BeautifulSoup(html) div = div_bf.find_all('div', class_ = 'listmain') a_bf = BeautifulSoup(str(div[0])) a = a_bf.find_all('a') for each in a: print(each.string, server + each.get('href'))
# -*- coding:UTF-8 -*- from bs4 import BeautifulSoup import requests, sys """ 類(lèi)說(shuō)明:下載《筆趣看》網(wǎng)小說(shuō)《一念永恒》 Parameters: 無(wú) Returns: 無(wú) Modify: 2017-09-13 """ class downloader(object): def __init__(self): self.server = 'http://www.biqukan.com/' self.target = 'http://www.biqukan.com/1_1094/' self.names = [] #存放章節(jié)名 self.urls = [] #存放章節(jié)鏈接 self.nums = 0 #章節(jié)數(shù) """ 函數(shù)說(shuō)明:獲取下載鏈接 Parameters: 無(wú) Returns: 無(wú) Modify: 2017-09-13 """ def get_download_url(self): req = requests.get(url = self.target) html = req.text div_bf = BeautifulSoup(html) div = div_bf.find_all('div', class_ = 'listmain') a_bf = BeautifulSoup(str(div[0])) a = a_bf.find_all('a') self.nums = len(a[15:]) #剔除不必要的章節(jié),并統(tǒng)計(jì)章節(jié)數(shù) for each in a[15:]: self.names.append(each.string) self.urls.append(self.server + each.get('href')) """ 函數(shù)說(shuō)明:獲取章節(jié)內(nèi)容 Parameters: target - 下載連接(string) Returns: texts - 章節(jié)內(nèi)容(string) Modify: 2017-09-13 """ def get_contents(self, target): req = requests.get(url = target) html = req.text bf = BeautifulSoup(html) texts = bf.find_all('div', class_ = 'showtxt') texts = texts[0].text.replace('\xa0'*8,'\n\n') return texts """ 函數(shù)說(shuō)明:將爬取的文章內(nèi)容寫(xiě)入文件 Parameters: name - 章節(jié)名稱(chēng)(string) path - 當(dāng)前路徑下,小說(shuō)保存名稱(chēng)(string) text - 章節(jié)內(nèi)容(string) Returns: 無(wú) Modify: 2017-09-13 """ def writer(self, name, path, text): write_flag = True with open(path, 'a', encoding='utf-8') as f: f.write(name + '\n') f.writelines(text) f.write('\n\n') if __name__ == "__main__": dl = downloader() dl.get_download_url() print('《一年永恒》開(kāi)始下載:') for i in range(dl.nums): dl.writer(dl.names[i], '一念永恒.txt', dl.get_contents(dl.urls[i])) sys.stdout.write(" 已下載:%.3f%%" % float(i/dl.nums) + '\r') sys.stdout.flush() print('《一年永恒》下載完成')
2. 優(yōu)美壁紙下載
<img alt="Snow-capped mountain slopes under blue sky" src="https://images.unsplash.com/photo-1428509774491-cfac96e12253?dpr=1&auto=compress,format&fit=crop&w=360&h=240&q=80&cs=tinysrgb&crop=" class="cV68d" style="width: 220px; height: 147px;">
使用requeusts獲取整個(gè)網(wǎng)頁(yè)的HTML信息;
使用Beautiful Soup解析HTML信息,找到所有<img>標(biāo)簽,提取src屬性,獲取圖片存放地址;
根據(jù)圖片存放地址,下載圖片。
# -*- coding:UTF-8 -*-
import requests
if __name__ == '__main__':
target = 'https://unsplash.com/'
req = requests.get(url=target)
print(req.text)
https://unsplash.com/photos/1PrQ2mHW-Fo/download?force=true
https://unsplash.com/photos/JX7nDtafBcU/download?force=true
https://unsplash.com/photos/HCVbP3zqX4k/download?force=true
獲取整個(gè)json數(shù)據(jù)
解析json數(shù)據(jù)
# -*- coding:UTF-8 -*-
import requests
if __name__ == '__main__':
target = 'http://unsplash.com/napi/feeds/home'
req = requests.get(url=target)
print(req.text)
# -*- coding:UTF-8 -*-
import requests
if __name__ == '__main__':
target = 'http://unsplash.com/napi/feeds/home'
req = requests.get(url=target, verify=False)
print(req.text)
User-Agent:這里面存放瀏覽器的信息??梢钥吹缴蠄D的參數(shù)值,它表示我是通過(guò)Windows的Chrome瀏覽器,訪(fǎng)問(wèn)的這個(gè)服務(wù)器。如果我們不設(shè)置這個(gè)參數(shù),用Python程序直接發(fā)送GET請(qǐng)求,服務(wù)器接受到的User-Agent信息就會(huì)是一個(gè)包含python字樣的User-Agent。如果后臺(tái)設(shè)計(jì)者驗(yàn)證這個(gè)User-Agent參數(shù)是否合法,不讓帶Python字樣的User-Agent訪(fǎng)問(wèn),這樣就起到了反爬蟲(chóng)的作用。這是一個(gè)最簡(jiǎn)單的,最常用的反爬蟲(chóng)手段。
Referer:這個(gè)參數(shù)也可以用于反爬蟲(chóng),它表示這個(gè)請(qǐng)求是從哪發(fā)出的??梢钥吹轿覀兺ㄟ^(guò)瀏覽器訪(fǎng)問(wèn)網(wǎng)站,這個(gè)請(qǐng)求是從https://unsplash.com/,這個(gè)地址發(fā)出的。如果后臺(tái)設(shè)計(jì)者,驗(yàn)證這個(gè)參數(shù),對(duì)于不是從這個(gè)地址跳轉(zhuǎn)過(guò)來(lái)的請(qǐng)求一律禁止訪(fǎng)問(wèn),這樣就也起到了反爬蟲(chóng)的作用。
authorization:這個(gè)參數(shù)是基于AAA模型中的身份驗(yàn)證信息允許訪(fǎng)問(wèn)一種資源的行為。在我們用瀏覽器訪(fǎng)問(wèn)的時(shí)候,服務(wù)器會(huì)為訪(fǎng)問(wèn)者分配這個(gè)用戶(hù)ID。如果后臺(tái)設(shè)計(jì)者,驗(yàn)證這個(gè)參數(shù),對(duì)于沒(méi)有用戶(hù)ID的請(qǐng)求一律禁止訪(fǎng)問(wèn),這樣就又起到了反爬蟲(chóng)的作用。
# -*- coding:UTF-8 -*-
import requests
if __name__ == '__main__':
target = 'http://unsplash.com/napi/feeds/home'
headers = {'authorization':'your Client-ID'}
req = requests.get(url=target, headers=headers, verify=False)
print(req.text)
# -*- coding:UTF-8 -*-
import requests, json
if __name__ == '__main__':
target = 'http://unsplash.com/napi/feeds/home'
headers = {'authorization':'your Client-ID'}
req = requests.get(url=target, headers=headers, verify=False)
html = json.loads(req.text)
next_page = html['next_page']
print('下一頁(yè)地址:',next_page)
for each in html['photos']:
print('圖片ID:',each['id'])
# -*- coding:UTF-8 -*-
import requests, json, time, sys
from contextlib import closing
class get_photos(object):
def __init__(self):
self.photos_id = []
self.download_server = 'https://unsplash.com/photos/xxx/download?force=trues'
self.target = 'http://unsplash.com/napi/feeds/home'
self.headers = {'authorization':'your Client-ID'}
"""
函數(shù)說(shuō)明:獲取圖片ID
Parameters:
無(wú)
Returns:
無(wú)
Modify:
2017-09-13
"""
def get_ids(self):
req = requests.get(url=self.target, headers=self.headers, verify=False)
html = json.loads(req.text)
next_page = html['next_page']
for each in html['photos']:
self.photos_id.append(each['id'])
time.sleep(1)
for i in range(4):
req = requests.get(url=next_page, headers=self.headers, verify=False)
html = json.loads(req.text)
next_page = html['next_page']
for each in html['photos']:
self.photos_id.append(each['id'])
time.sleep(1)
"""
函數(shù)說(shuō)明:圖片下載
Parameters:
無(wú)
Returns:
無(wú)
Modify:
2017-09-13
"""
def download(self, photo_id, filename):
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36'}
target = self.download_server.replace('xxx', photo_id)
with closing(requests.get(url=target, stream=True, verify = False, headers = self.headers)) as r:
with open('%d.jpg' % filename, 'ab+') as f:
for chunk in r.iter_content(chunk_size = 1024):
if chunk:
f.write(chunk)
f.flush()
if __name__ == '__main__':
gp = get_photos()
print('獲取圖片連接中:')
gp.get_ids()
print('圖片下載中:')
for i in range(len(gp.photos_id)):
print(' 正在下載第%d張圖片' % (i+1))
gp.download(gp.photos_id[i], (i+1))
http://api.xfsub.com/index.php?url=[播放地址或視頻id]
http://api.xfsub.com/index.php?url=http://www.iqiyi.com/v_19rr7qhfg0.html#vfrm=19-9-0-1
xfsub_api\/url.php?key=02896e4af69fb18f70129b6046d7c718&time=1505724557&url=http%3A%2F%2Fwww.iqiyi.com%2Fv_19rr7qhfg0.html&type=&xml=1
xfsub_api/url.php?key=02896e4af69fb18f70129b6046d7c718&time=1505724557&url=http://www.iqiyi.com/v_19rr7qhfg0.html&type=&xml=1
http://api.xfsub.com/xfsub_api\url.php?key=02896e4af69fb18f70129b6046d7c718&time=1505724557&url=http://www.iqiyi.com/v_19rr7qhfg0.html&type=&xml=1
http://disp.titan.mgtv.com/vod.do?fmt=4&pno=1121&fid=1FEA2622E0BD9A1CA625FBE9B5A238A6&file=/c1/2017/09/06_0/1FEA2622E0BD9A1CA625FBE9B5A238A6_20170906_1_1_705.mp4
用正則表達(dá)式匹配到key、time、url等信息。
根據(jù)匹配的到信息發(fā)POST請(qǐng)求,獲得一個(gè)存放視頻信息的url。
根據(jù)這個(gè)url獲得視頻存放的地址。
根據(jù)最終的視頻地址,下載視頻。
爬蟲(chóng)時(shí)效性低,同樣的思路過(guò)了一個(gè)月,甚至一周可能無(wú)法使用,但是爬取思路都是如此,完全可以自行分析。
本次實(shí)戰(zhàn)代碼,均已上傳我的Github,歡迎Follow、Star:
https://github.com/Jack-Cherish/python-spider
如有問(wèn)題,請(qǐng)留言。如有錯(cuò)誤,還望指正,謝謝!
如對(duì)本文有疑問(wèn),請(qǐng)?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會(huì)為你解答??! 點(diǎn)擊進(jìn)入論壇