一小時(shí)入門 Python 3 網(wǎng)絡(luò)爬蟲(chóng)

聲明:本文講解的實(shí)戰(zhàn)內(nèi)容,均僅用于學(xué)習(xí)交流,請(qǐng)勿用于任何商業(yè)用途!

一、前言

強(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)寫爬蟲(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(wǎng)站也可以"整容"嗎?可以!請(qǐng)看下圖:

我能有這么多錢嗎?顯然不可能。我是怎么給網(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ō)這么多,什么意思呢?瀏覽器就是作為客戶端從服務(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

使用pip和easy_install都可以安裝,二選一即可。

(2)簡(jiǎn)單實(shí)例

安裝好requests庫(kù)之后,我們先來(lái)大體瀏覽一下requests庫(kù)的基礎(chǔ)方法:

官方中文教程地址:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

requests庫(kù)的開(kāi)發(fā)者為我們提供了詳細(xì)的中文教程,查詢起來(lái)很方便。本文不會(huì)對(duì)其所有內(nèi)容進(jìn)行講解,摘取其部分使用到的內(nèi)容,進(jìn)行實(shí)戰(zhàn)說(shuō)明。

首先,讓我們看下requests.get()方法,它用于向服務(wù)器發(fā)起GET請(qǐng)求,不了解GET請(qǐng)求沒(méi)有關(guān)系。我們可以這樣理解:get的中文意思是得到、抓住,那這個(gè)requests.get()方法就是從服務(wù)器得到、抓住數(shù)據(jù),也就是獲取數(shù)據(jù)。讓我們看一個(gè)例子(以 www.gitbook.cn? 為例)來(lái)加深理解:

# -*- coding:UTF-8 -*-

import requests

if __name__ == '__main__':

target = 'http://gitbook.cn/'

req = requests.get(url=target)

print(req.text)

requests.get()方法必須設(shè)置的一個(gè)參數(shù)就是url,因?yàn)槲覀兊酶嬖VGET請(qǐng)求,我們的目標(biāo)是誰(shuí),我們要獲取誰(shuí)的信息。我們將GET請(qǐng)求獲得的響應(yīng)內(nèi)容存放到req變量中,然后使用req.text就可以獲得HTML信息了。運(yùn)行結(jié)果如下:

左側(cè)是我們程序獲得的結(jié)果,右側(cè)是我們?cè)趙ww.gitbook.cn? 網(wǎng)站審查元素獲得的信息。我們可以看到,我們已經(jīng)順利獲得了該網(wǎng)頁(yè)的HTML信息。這就是一個(gè)最簡(jiǎn)單的爬蟲(chóng)實(shí)例,可能你會(huì)問(wèn),我只是爬取了這個(gè)網(wǎng)頁(yè)的HTML信息,有什么用呢?客官稍安勿躁,接下來(lái)進(jìn)入我們的實(shí)戰(zhàn)正文。

三、爬蟲(chóng)實(shí)戰(zhàn)

實(shí)戰(zhàn)內(nèi)容由簡(jiǎn)單到復(fù)雜,難度逐漸增加,但均屬于入門級(jí)難度。下面開(kāi)始我們的第一個(gè)實(shí)戰(zhàn)內(nèi)容:網(wǎng)絡(luò)小說(shuō)下載。

1. 小說(shuō)下載

(1)實(shí)戰(zhàn)背景

小說(shuō)網(wǎng)站《筆趣看》URL:http://www.biqukan.com/

《筆趣看》是一個(gè)盜版小說(shuō)網(wǎng)站,這里有很多起點(diǎn)中文網(wǎng)的小說(shuō),該網(wǎng)站小說(shuō)的更新速度稍滯后于起點(diǎn)中文網(wǎng)正版小說(shuō)的更新速度。并且該網(wǎng)站只支持在線瀏覽,不支持小說(shuō)打包下載。因此,本次實(shí)戰(zhàn)就是從該網(wǎng)站爬取并保存一本名為《一念永恒》的小說(shuō),該小說(shuō)是耳根正在連載中的一部玄幻小說(shuō)。PS:本實(shí)例僅為交流學(xué)習(xí),支持耳根大大,請(qǐng)上起點(diǎn)中文網(wǎng)訂閱。

(2)小試牛刀

我們先看下《一念永恒》小說(shuō)的第一章內(nèi)容,URL:http://www.biqukan.com/1_1094/5403177.html

用已經(jīng)學(xué)到的知識(shí)獲取HTML信息試一試,編寫代碼如下:

# -*- 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)

運(yùn)行代碼,可以看到如下結(jié)果:

可以看到,我們很輕松地獲取了HTML信息。但是,很顯然,很多信息是我們不想看到的,我們只想獲得如右側(cè)所示的正文內(nèi)容,我們不關(guān)心那些看著眼暈的英文字母。如何把正文內(nèi)容從這些眾多的HTML信息中提取出來(lái)呢?這就是本小節(jié)實(shí)戰(zhàn)的主要內(nèi)容。

(3)Beautiful Soup

爬蟲(chóng)的第一步,獲取整個(gè)網(wǎng)頁(yè)的HTML信息,我們已經(jīng)完成。接下來(lái)就是爬蟲(chóng)的第二步,解析HTML信息,提取我們感興趣的內(nèi)容。對(duì)于本小節(jié)的實(shí)戰(zhàn),我們感興趣的內(nèi)容就是文章的正文。提取的方法有很多,例如使用正則表達(dá)式、Xpath、Beautiful Soup等。對(duì)于初學(xué)者而言,最容易理解,并且使用簡(jiǎn)單的方法就是使用Beautiful Soup提取感興趣內(nèi)容。

Beautiful Soup的安裝方法和requests一樣,使用如下指令安裝(也是二選一):

pip install beautifulsoup4

easy_install beautifulsoup4

一個(gè)強(qiáng)大的第三方庫(kù),都會(huì)有一個(gè)詳細(xì)的官方文檔。我們很幸運(yùn),Beautiful Soup也是有中文的官方文檔。URL:http://beautifulsoup.readthedocs.io/zh_CN/latest/

同理,我會(huì)根據(jù)實(shí)戰(zhàn)需求,講解Beautiful Soup庫(kù)的部分使用方法,更詳細(xì)的內(nèi)容,請(qǐng)查看官方文檔。

現(xiàn)在,我們使用已經(jīng)掌握的審查元素方法,查看一下我們的目標(biāo)頁(yè)面,你會(huì)看到如下內(nèi)容:

不難發(fā)現(xiàn),文章的所有內(nèi)容都放在了一個(gè)名為div的“東西下面”,這個(gè)"東西"就是html標(biāo)簽。HTML標(biāo)簽是HTML語(yǔ)言中最基本的單位,HTML標(biāo)簽是HTML最重要的組成部分。不理解,沒(méi)關(guān)系,我們?cè)倥e個(gè)簡(jiǎn)單的例子:一個(gè)女人的包包里,會(huì)有很多東西,她們會(huì)根據(jù)自己的習(xí)慣將自己的東西進(jìn)行分類。鏡子和口紅這些會(huì)經(jīng)常用到的東西,回歸放到容易拿到的外側(cè)口袋里。那些不經(jīng)常用到,需要注意安全存放的證件會(huì)被放到不容易拿到的里側(cè)口袋里。

html標(biāo)簽就像一個(gè)個(gè)“口袋”,每個(gè)“口袋”都有自己的特定功能,負(fù)責(zé)存放不同的內(nèi)容。顯然,上述例子中的div標(biāo)簽下存放了我們關(guān)心的正文內(nèi)容。這個(gè)div標(biāo)簽是這樣的:

細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn),除了div字樣外,還有id和class。id和class就是div標(biāo)簽的屬性,content和showtxt是屬性值,一個(gè)屬性對(duì)應(yīng)一個(gè)屬性值。這東西有什么用?它是用來(lái)區(qū)分不同的div標(biāo)簽的,因?yàn)閐iv標(biāo)簽可以有很多,我們?cè)趺醇右詤^(qū)分不同的div標(biāo)簽?zāi)兀烤褪峭ㄟ^(guò)不同的屬性值。

仔細(xì)觀察目標(biāo)網(wǎng)站一番,我們會(huì)發(fā)現(xiàn)這樣一個(gè)事實(shí):class屬性為showtxt的div標(biāo)簽,獨(dú)一份!這個(gè)標(biāo)簽里面存放的內(nèi)容,是我們關(guān)心的正文部分。

知道這個(gè)信息,我們就可以使用Beautiful Soup提取我們想要的內(nèi)容了,編寫代碼如下:

# -*- 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)

在解析html之前,我們需要?jiǎng)?chuàng)建一個(gè)Beautiful Soup對(duì)象。BeautifulSoup函數(shù)里的參數(shù)就是我們已經(jīng)獲得的html信息。然后我們使用find_all方法,獲得html信息中所有class屬性為showtxt的div標(biāo)簽。find_all方法的第一個(gè)參數(shù)是獲取的標(biāo)簽名,第二個(gè)參數(shù)class_是標(biāo)簽的屬性,為什么不是class,而帶了一個(gè)下劃線呢?因?yàn)閜ython中class是關(guān)鍵字,為了防止沖突,這里使用class_表示標(biāo)簽的class屬性,class_后面跟著的showtxt就是屬性值了。看下我們要匹配的標(biāo)簽格式:

這樣對(duì)應(yīng)的看一下,是不是就懂了?可能有人會(huì)問(wèn)了,為什么不是find_all('div', id = 'content', class_ = 'showtxt')?這樣其實(shí)也是可以的,屬性是作為查詢時(shí)候的約束條件,添加一個(gè)class_='showtxt'條件,我們就已經(jīng)能夠準(zhǔn)確匹配到我們想要的標(biāo)簽了,所以我們就不必再添加id這個(gè)屬性了。運(yùn)行代碼查看我們匹配的結(jié)果:

我們可以看到,我們已經(jīng)順利匹配到我們關(guān)心的正文內(nèi)容,但是還有一些我們不想要的東西。比如div標(biāo)簽名,br標(biāo)簽,以及各種空格。怎么去除這些東西呢?我們繼續(xù)編寫代碼:

# -*- 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'))

find_all匹配的返回的結(jié)果是一個(gè)列表。提取匹配結(jié)果后,使用text屬性,提取文本內(nèi)容,濾除br標(biāo)簽。隨后使用replace方法,剔除空格,替換為回車進(jìn)行分段。 在html中是用來(lái)表示空格的。replace('\xa0'*8,'\n\n')就是去掉下圖的八個(gè)空格符號(hào),并用回車代替:

程序運(yùn)行結(jié)果如下:

可以看到,我們很自然的匹配到了所有正文內(nèi)容,并進(jìn)行了分段。我們已經(jīng)順利獲得了一個(gè)章節(jié)的內(nèi)容,要想下載正本小說(shuō),我們就要獲取每個(gè)章節(jié)的鏈接。我們先分析下小說(shuō)目錄,URL:http://www.biqukan.com/1_1094/

通過(guò)審查元素,我們發(fā)現(xiàn)可以發(fā)現(xiàn),這些章節(jié)都存放在了class屬性為listmain的div標(biāo)簽下,選取部分html代碼如下:

《一念永恒》最新章節(jié)列表

第1027章 第十道門

第1026章 絕倫道法!

第1025章 長(zhǎng)生燈!

第1024章 一目晶淵

第1023章 通天道門

第1022章 四大兇獸!

第1021章 鱷首!

第1020章 一觸即發(fā)!

第1019章 魁祖的氣息!

第1018章 絕望的魁皇城

第1017章 我還是恨你!

第1016章 從來(lái)沒(méi)有世界之門!

《一念永恒》正文卷

外傳1 柯父。

外傳2 楚玉嫣。

外傳3 鸚鵡與皮凍。

第一章 他叫白小純

第二章 火灶房

第三章 六句真言

第四章 煉靈

在分析之前,讓我們先介紹一個(gè)概念:父節(jié)點(diǎn)、子節(jié)點(diǎn)、孫節(jié)點(diǎn)。

限定了

標(biāo)簽的開(kāi)始和結(jié)束的位置,他們是成對(duì)出現(xiàn)的,有開(kāi)始位置,就有結(jié)束位置。我們可以看到,在

標(biāo)簽包含

標(biāo)簽,那這個(gè)

標(biāo)簽就是

標(biāo)簽的子節(jié)點(diǎn),

標(biāo)簽又包含標(biāo)簽和

標(biāo)簽,那么

標(biāo)簽和

標(biāo)簽就是

標(biāo)簽的孫節(jié)點(diǎn)。有點(diǎn)繞?那你記住這句話:誰(shuí)包含誰(shuí),誰(shuí)就是誰(shuí)兒子!

他們之間的關(guān)系都是相對(duì)的。比如對(duì)于

標(biāo)簽,它的子節(jié)點(diǎn)是標(biāo)簽,它的父節(jié)點(diǎn)是

標(biāo)簽。這跟我們?nèi)耸且粯拥模嫌欣舷掠行 ?/p>

看到這里可能有人會(huì)問(wèn),這有好多

標(biāo)簽和標(biāo)簽啊!不同的

標(biāo)簽,它們是什么關(guān)系啊?顯然,兄弟姐妹嘍!我們稱它們?yōu)樾值芙Y(jié)點(diǎn)。

好了,概念明確清楚,接下來(lái),讓我們分析一下問(wèn)題。我們看到每個(gè)章節(jié)的名字存放在了標(biāo)簽里面。標(biāo)簽還有一個(gè)href屬性。這里就不得不提一下標(biāo)簽的定義了,標(biāo)簽定義了一個(gè)超鏈接,用于從一張頁(yè)面鏈接到另一張頁(yè)面。標(biāo)簽最重要的屬性是 href 屬性,它指示鏈接的目標(biāo)。

我們將之前獲得的第一章節(jié)的URL和標(biāo)簽對(duì)比看一下:

http://www.biqukan.com/1_1094/5403177.html

第一章 他叫白小純

不難發(fā)現(xiàn),標(biāo)簽中href屬性存放的屬性值/1_1094/5403177.html是章節(jié)URLhttp://www.biqukan.com/1_1094/5403177.html的后半部分。其他章節(jié)也是如此!那這樣,我們就可以根據(jù)標(biāo)簽的href屬性值獲得每個(gè)章節(jié)的鏈接和名稱了。

總結(jié)一下:小說(shuō)每章的鏈接放在了class屬性為listmain的

標(biāo)簽下的標(biāo)簽中。鏈接具體位置放在html->body->div->dl->dd->a的href屬性中。先匹配class屬性為listmain的

標(biāo)簽,再匹配標(biāo)簽。編寫代碼如下:

# -*- 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])

還是使用find_all方法,運(yùn)行結(jié)果如下:

很順利,接下來(lái)再匹配每一個(gè)標(biāo)簽,并提取章節(jié)名和章節(jié)文章。如果我們使用Beautiful Soup匹配到了下面這個(gè)標(biāo)簽,如何提取它的href屬性和標(biāo)簽里存放的章節(jié)名呢?

第一章 他叫白小純

方法很簡(jiǎn)單,對(duì)Beautiful Soup返回的匹配結(jié)果a,使用a.get('href')方法就能獲取href的屬性值,使用a.string就能獲取章節(jié)名,編寫代碼如下:

# -*- 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'))

因?yàn)閒ind_all返回的是一個(gè)列表,里邊存放了很多的標(biāo)簽,所以使用for循環(huán)遍歷每個(gè)標(biāo)簽并打印出來(lái),運(yùn)行結(jié)果如下。

最上面匹配的一千多章的內(nèi)容是最新更新的12章節(jié)的鏈接。這12章內(nèi)容會(huì)和下面的重復(fù),所以我們要濾除,除此之外,還有那3個(gè)外傳,我們也不想要。這些都簡(jiǎn)單地剔除就好。

(3)整合代碼

每個(gè)章節(jié)的鏈接、章節(jié)名、章節(jié)內(nèi)容都有了。接下來(lái)就是整合代碼,將獲得內(nèi)容寫入文本文件存儲(chǔ)就好了。編寫代碼如下:

# -*- coding:UTF-8 -*-

from bs4 import BeautifulSoup

import requests, sys

"""

類說(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)容寫入文件

Parameters:

name - 章節(jié)名稱(string)

path - 當(dāng)前路徑下,小說(shuō)保存名稱(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('《一年永恒》下載完成')

很簡(jiǎn)單的程序,單進(jìn)程跑,沒(méi)有開(kāi)進(jìn)程池。下載速度略慢,喝杯茶休息休息吧。代碼運(yùn)行效果如下圖所示:

2. 優(yōu)美壁紙下載

(1)實(shí)戰(zhàn)背景

已經(jīng)會(huì)爬取文字了,是不是感覺(jué)爬蟲(chóng)還是蠻好玩的呢?接下來(lái),讓我們進(jìn)行一個(gè)進(jìn)階實(shí)戰(zhàn),了解一下反爬蟲(chóng)。URL:https://unsplash.com/

看一看這些優(yōu)美的壁紙,這個(gè)網(wǎng)站的名字叫做Unsplash,免費(fèi)高清壁紙分享網(wǎng)是一個(gè)堅(jiān)持每天分享高清的攝影圖片的站點(diǎn),每天更新一張高質(zhì)量的圖片素材,全是生活中的景象作品,清新的生活氣息圖片可以作為桌面壁紙也可以應(yīng)用于各種需要的環(huán)境。

看到這么優(yōu)美的圖片,我的第一反應(yīng)就是想收藏一些,作為知乎文章的題圖再好不過(guò)了。每張圖片我都很喜歡,批量下載吧,不多爬,就下載50張好了。

(2)實(shí)戰(zhàn)進(jìn)階

我們已經(jīng)知道了每個(gè)html標(biāo)簽都有各自的功能。標(biāo)簽存放一下超鏈接,圖片存放在哪個(gè)標(biāo)簽里呢?html規(guī)定,圖片統(tǒng)統(tǒng)給我放到

標(biāo)簽中!既然這樣,我們截取就Unsplash網(wǎng)站中的一個(gè)

need-to-insert-img

標(biāo)簽,分析一下:

need-to-insert-img

可以看到,

標(biāo)簽有很多屬性,有alt、src、class、style屬性,其中src屬性存放的就是我們需要的圖片保存地址,我們根據(jù)這個(gè)地址就可以進(jìn)行圖片的下載。

need-to-insert-img

那么,讓我們先捋一捋這個(gè)過(guò)程:

使用requeusts獲取整個(gè)網(wǎng)頁(yè)的HTML信息;

使用Beautiful Soup解析HTML信息,找到所有

標(biāo)簽,提取src屬性,獲取圖片存放地址;

need-to-insert-img

根據(jù)圖片存放地址,下載圖片。

我們信心滿滿地按照這個(gè)思路爬取Unsplash試一試,編寫代碼如下:

# -*- coding:UTF-8 -*-

import requests

if __name__ == '__main__':

target = 'https://unsplash.com/'

req = requests.get(url=target)

print(req.text)

按照我們的設(shè)想,我們應(yīng)該能找到很多

標(biāo)簽。但是我們發(fā)現(xiàn),除了一些

need-to-insert-img

答案就是,這個(gè)網(wǎng)站的所有圖片都是動(dòng)態(tài)加載的!網(wǎng)站有靜態(tài)網(wǎng)站和動(dòng)態(tài)網(wǎng)站之分,上一個(gè)實(shí)戰(zhàn)爬取的網(wǎng)站是靜態(tài)網(wǎng)站,而這個(gè)網(wǎng)站是動(dòng)態(tài)網(wǎng)站,動(dòng)態(tài)加載有一部分的目的就是為了反爬蟲(chóng)。

對(duì)于什么是動(dòng)態(tài)加載,你可以這樣理解:

我們知道化妝術(shù)學(xué)的好,賊厲害,可以改變一個(gè)人的容貌。相應(yīng)的,動(dòng)態(tài)加載用的好,也賊厲害,可以改變一個(gè)網(wǎng)站的容貌。

動(dòng)態(tài)網(wǎng)站使用動(dòng)態(tài)加載常用的手段就是通過(guò)調(diào)用JavaScript來(lái)實(shí)現(xiàn)的。怎么實(shí)現(xiàn)JavaScript動(dòng)態(tài)加載,我們不必深究,我們只要知道,動(dòng)態(tài)加載的JavaScript腳本,就像化妝術(shù)需要用的化妝品,五花八門。有粉底、口紅、睫毛膏等等,它們都有各自的用途。動(dòng)態(tài)加載的JavaScript腳本也一樣,一個(gè)動(dòng)態(tài)加載的網(wǎng)站可能使用很多JavaScript腳本,我們只要找到負(fù)責(zé)動(dòng)態(tài)加載圖片的JavaScript腳本,不就找到我們需要的鏈接了嗎?

對(duì)于初學(xué)者,我們不必看懂JavaScript執(zhí)行的內(nèi)容是什么,做了哪些事情,因?yàn)槲覀冇袕?qiáng)大的抓包工具,它自然會(huì)幫我們分析。這個(gè)強(qiáng)大的抓包工具就是Fiddler。URL:http://www.telerik.com/fiddler

PS:也可以使用瀏覽器自帶的Networks,但是我更推薦這個(gè)軟件,因?yàn)樗僮髌饋?lái)更高效。

安裝方法很簡(jiǎn)單,傻瓜式安裝,一直下一步即可,對(duì)于經(jīng)常使用電腦的人來(lái)說(shuō),應(yīng)該沒(méi)有任何難度。

這個(gè)軟件的使用方法也很簡(jiǎn)單,打開(kāi)軟件,然后用瀏覽器打開(kāi)我們的目標(biāo)網(wǎng)站,以Unsplash為例,抓包結(jié)果如下:

我們可以看到,上圖左側(cè)紅框處是我們的GET請(qǐng)求的地址,就是網(wǎng)站的URL,右下角是服務(wù)器返回的信息,我們可以看到,這些信息也是我們上一個(gè)程序獲得的信息。這個(gè)不是我們需要的鏈接,我們繼續(xù)往下看。

我們發(fā)現(xiàn)上圖所示的就是一個(gè)JavaScript請(qǐng)求,看右下側(cè)服務(wù)器返回的信息是一個(gè)json格式的數(shù)據(jù)。這里面,就有我們需要的內(nèi)容。我們局部放大看一下:

這是Fiddler右側(cè)的信息,上面是請(qǐng)求的Headers信息,包括這個(gè)Javascript的請(qǐng)求地 址:http://unsplash.com/napi/feeds/home,其他信息我們先不管,我們看看下面的內(nèi)容。里面有很多圖片的信息,包括圖片的id,圖片的大小,圖片的鏈接,還有下一頁(yè)的地址。這個(gè)腳本以json格式存儲(chǔ)傳輸?shù)臄?shù)據(jù),json格式是一種輕量級(jí)的數(shù)據(jù)交換格式,起到封裝數(shù)據(jù)的作用,易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成。這么多鏈接,可以看到圖片的鏈接有很多,根據(jù)哪個(gè)鏈接下載圖片呢?先別急,讓我們繼續(xù)分析:

在這個(gè)網(wǎng)站,我們可以按這個(gè)按鈕進(jìn)行圖片下載。我們抓包分下下這個(gè)動(dòng)作,看看發(fā)送了哪些請(qǐng)求。

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

通過(guò)Fiddler抓包,我們發(fā)現(xiàn),點(diǎn)擊不同圖片的下載按鈕,GET請(qǐng)求的地址都是不同的。但是它們很有規(guī)律,就是中間有一段代碼是不一樣的,其他地方都一樣。中間那段代碼是不是很熟悉?沒(méi)錯(cuò),它就是我們之前抓包分析得到j(luò)son數(shù)據(jù)中的照片的id。我們只要解析出每個(gè)照片的id,就可以獲得圖片下載的請(qǐng)求地址,然后根據(jù)這個(gè)請(qǐng)求地址,我們就可以下載圖片了。那么,現(xiàn)在的首要任務(wù)就是解析json數(shù)據(jù)了。

json格式的數(shù)據(jù)也是分層的。可以看到next_page里存放的是下一頁(yè)的請(qǐng)求地址,很顯然Unsplash下一頁(yè)的內(nèi)容,也是動(dòng)態(tài)加載的。在photos下面的id里,存放著圖片的id,這個(gè)就是我們需要獲得的圖片id號(hào)。

怎么編程提取這些json數(shù)據(jù)呢?我們也是分步完成:

獲取整個(gè)json數(shù)據(jù)

解析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)

很遺憾,程序報(bào)錯(cuò)了,問(wèn)題出在哪里?通過(guò)錯(cuò)誤信息,我們可以看到SSL認(rèn)證錯(cuò)誤,SSL認(rèn)證是指客戶端到服務(wù)器端的認(rèn)證。一個(gè)非常簡(jiǎn)單的解決這個(gè)認(rèn)證錯(cuò)誤的方法就是設(shè)置requests.get()方法的verify參數(shù)。這個(gè)參數(shù)默認(rèn)設(shè)置為True,也就是執(zhí)行認(rèn)證。我們將其設(shè)置為False,繞過(guò)認(rèn)證不就可以了?

有想法就要嘗試,編寫代碼如下:

# -*- 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)

認(rèn)證問(wèn)題解決了,又有新問(wèn)題了:

可以看到,我們GET請(qǐng)求又失敗了,這是為什么?這個(gè)網(wǎng)站反爬蟲(chóng)的手段除了動(dòng)態(tài)加載,還有一個(gè)反爬蟲(chóng)手段,那就是驗(yàn)證Request Headers。接下來(lái),讓我們分析下這個(gè)Requests Headers:

我截取了Fiddler的抓包信息,可以看到Requests Headers里又很多參數(shù),有Accept、Accept-Encoding、Accept-Language、DPR、User-Agent、Viewport-Width、accept-version、Referer、x-unsplash-client、authorization、Connection、Host。它們都是什么意思呢?

專業(yè)的解釋能說(shuō)的太多,我挑重點(diǎn):

User-Agent:這里面存放瀏覽器的信息。可以看到上圖的參數(shù)值,它表示我是通過(guò)Windows的Chrome瀏覽器,訪問(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訪問(wèn),這樣就起到了反爬蟲(chóng)的作用。這是一個(gè)最簡(jiǎn)單的,最常用的反爬蟲(chóng)手段。

Referer:這個(gè)參數(shù)也可以用于反爬蟲(chóng),它表示這個(gè)請(qǐng)求是從哪發(fā)出的。可以看到我們通過(guò)瀏覽器訪問(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)求一律禁止訪問(wèn),這樣就也起到了反爬蟲(chóng)的作用。

authorization:這個(gè)參數(shù)是基于AAA模型中的身份驗(yàn)證信息允許訪問(wèn)一種資源的行為。在我們用瀏覽器訪問(wèn)的時(shí)候,服務(wù)器會(huì)為訪問(wèn)者分配這個(gè)用戶ID。如果后臺(tái)設(shè)計(jì)者,驗(yàn)證這個(gè)參數(shù),對(duì)于沒(méi)有用戶ID的請(qǐng)求一律禁止訪問(wèn),這樣就又起到了反爬蟲(chóng)的作用。

Unsplash是根據(jù)哪個(gè)參數(shù)反爬蟲(chóng)的呢?根據(jù)我的測(cè)試,是authorization。我們只要通過(guò)程序手動(dòng)添加這個(gè)參數(shù),然后再發(fā)送GET請(qǐng)求,就可以順利訪問(wèn)了。怎么什么設(shè)置呢?還是requests.get()方法,我們只需要添加headers參數(shù)即可。編寫代碼如下:

# -*- 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)

headers參數(shù)值是通過(guò)字典傳入的。記得將上述代碼中your Client-ID換成諸位自己抓包獲得的信息。代碼運(yùn)行結(jié)果如下:

皇天不負(fù)有心人,可以看到我們已經(jīng)順利獲得json數(shù)據(jù)了,里面有next_page和照片的id。接下來(lái)就是解析json數(shù)據(jù)。根據(jù)我們之前分析可知,next_page放在了json數(shù)據(jù)的最外側(cè),照片的id放在了photos->id里。我們使用json.load()方法解析數(shù)據(jù),編寫代碼如下:

# -*- 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'])

解析json數(shù)據(jù)很簡(jiǎn)單,跟字典操作一樣,就是字典套字典。json.load()里面的參數(shù)是原始的json格式的數(shù)據(jù)。程序運(yùn)行結(jié)果如下:

圖片的ID已經(jīng)獲得了,再通過(guò)字符串處理一下,就生成了我們需要的圖片下載請(qǐng)求地址。根據(jù)這個(gè)地址,我們就可以下載圖片了。下載方式,使用直接寫入文件的方法。

(3)整合代碼

每次獲取鏈接加一個(gè)1s延時(shí),因?yàn)槿嗽跒g覽頁(yè)面的時(shí)候,翻頁(yè)的動(dòng)作不可能太快。我們要讓我們的爬蟲(chóng)盡量友好一些。

# -*- 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))

下載速度還行,有的圖片下載慢是因?yàn)閳D片太大。可以看到右側(cè)也打印了一些警報(bào)信息,這是因?yàn)槲覀儧](méi)有進(jìn)行SSL驗(yàn)證。

學(xué)會(huì)了爬取圖片,簡(jiǎn)單的動(dòng)態(tài)加載的網(wǎng)站也難不倒你了。趕快試試國(guó)內(nèi)的一些圖片網(wǎng)站吧!

3. 愛(ài)奇藝VIP視頻下載

(1)實(shí)戰(zhàn)背景

愛(ài)奇藝的VIP視頻只有會(huì)員能看,普通用戶只能看前6分鐘。比如加勒比海盜5的URL:http://www.iqiyi.com/v_19rr7qhfg0.html#vfrm=19-9-0-1

我們?cè)趺疵赓M(fèi)看VIP視頻呢?一個(gè)簡(jiǎn)單的方法,就是通過(guò)旋風(fēng)視頻VIP解析網(wǎng)站。URL:http://api.xfsub.com/

這個(gè)網(wǎng)站為我們提供了免費(fèi)的視頻解析,它的通用解析方式是:

http://api.xfsub.com/index.php?url=[播放地址或視頻id]

比如,對(duì)于繡春刀這個(gè)電影,我們只需要在瀏覽器地址欄輸入:

http://api.xfsub.com/index.php?url=http://www.iqiyi.com/v_19rr7qhfg0.html#vfrm=19-9-0-1

這樣,我們就可以在線觀看這些VIP視頻了:

但是這個(gè)網(wǎng)站只提供了在線解析視頻的功能,沒(méi)有提供下載接口,如果想把視頻下載下來(lái),我們就可以利用網(wǎng)絡(luò)爬蟲(chóng)進(jìn)行抓包,將視頻下載下來(lái)。

(2)實(shí)戰(zhàn)升級(jí)

分析方法相同,我們使用Fiddler進(jìn)行抓包:

我們可以看到,有用的請(qǐng)求并不多,我們逐條分析。我們先看第一個(gè)請(qǐng)求返回的信息。

可以看到第一個(gè)請(qǐng)求是GET請(qǐng)求,沒(méi)有什么有用的信息,繼續(xù)看下一條。

我們看到,第二條GET請(qǐng)求地址變了,并且在返回的信息中,我們看到,這個(gè)網(wǎng)頁(yè)執(zhí)行了一個(gè)POST請(qǐng)求。POST請(qǐng)求是啥呢?它跟GET請(qǐng)求正好相反,GET是從服務(wù)器獲得數(shù)據(jù),而POST請(qǐng)求是向服務(wù)器發(fā)送數(shù)據(jù),服務(wù)器再根據(jù)POST請(qǐng)求的參數(shù),返回相應(yīng)的內(nèi)容。這個(gè)POST請(qǐng)求有四個(gè)參數(shù),分別為time、key、url、type。記住這個(gè)有用的信息,我們?cè)谧グY(jié)果中,找一下這個(gè)請(qǐng)求,看看這個(gè)POST請(qǐng)求做了什么。

很顯然,這個(gè)就是我們要找的POST請(qǐng)求,我們可以看到POST請(qǐng)求的參數(shù)以及返回的json格式的數(shù)據(jù)。其中url存放的參數(shù)如下:

xfsub_api\/url.php?key=02896e4af69fb18f70129b6046d7c718&time=1505724557&url=http%3A%2F%2Fwww.iqiyi.com%2Fv_19rr7qhfg0.html&type=&xml=1

這個(gè)信息有轉(zhuǎn)義了,但是沒(méi)有關(guān)系,我們手動(dòng)提取一下,變成如下形式:

xfsub_api/url.php?key=02896e4af69fb18f70129b6046d7c718&time=1505724557&url=http://www.iqiyi.com/v_19rr7qhfg0.html&type=&xml=1

我們已經(jīng)知道了這個(gè)解析視頻的服務(wù)器的域名,再把域名加上:

http://api.xfsub.com/xfsub_api\url.php?key=02896e4af69fb18f70129b6046d7c718&time=1505724557&url=http://www.iqiyi.com/v_19rr7qhfg0.html&type=&xml=1

這里面存放的是什么東西?不會(huì)視頻解析后的地址吧?我們有瀏覽器打開(kāi)這個(gè)地址看一下:

果然,我們可以看到視頻地址近在眼前啊,URL如下:

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

我們?cè)俅蜷_(kāi)這個(gè)視頻地址:

瞧,我們就這樣得到了這個(gè)視頻在服務(wù)器上的緩存地址。根據(jù)這個(gè)地址,我們就可以輕松下載視頻了。

PS:需要注意一點(diǎn),這些URL地址,都是有一定時(shí)效性的,很快就會(huì)失效,因?yàn)槔锩姘瑫r(shí)間信息。所以,各位在分析的時(shí)候,要根據(jù)自己的URL結(jié)果打開(kāi)網(wǎng)站才能看到視頻。

接下來(lái),我們的任務(wù)就是編程實(shí)現(xiàn)我們所分析的步驟,根據(jù)不同的視頻播放地址獲得視頻存放的地址。

現(xiàn)在梳理一下編程思路:

用正則表達(dá)式匹配到key、time、url等信息。

根據(jù)匹配的到信息發(fā)POST請(qǐng)求,獲得一個(gè)存放視頻信息的url。

根據(jù)這個(gè)url獲得視頻存放的地址。

根據(jù)最終的視頻地址,下載視頻。

(3)編寫代碼

編寫代碼的時(shí)候注意一個(gè)問(wèn)題,就是我們需要使用requests.session()保持我們的會(huì)話請(qǐng)求。簡(jiǎn)單理解就是,在初次訪問(wèn)服務(wù)器的時(shí)候,服務(wù)器會(huì)給你分配一個(gè)身份證明。我們需要拿著這個(gè)身份證去繼續(xù)訪問(wèn),如果沒(méi)有這個(gè)身份證明,服務(wù)器就不會(huì)再讓你訪問(wèn)。這也就是這個(gè)服務(wù)器的反爬蟲(chóng)手段,會(huì)驗(yàn)證用戶的身份。

思路已經(jīng)給出,希望喜歡爬蟲(chóng)的人可以在運(yùn)行下代碼之后,自己重頭編寫程序,因?yàn)橹挥薪?jīng)過(guò)自己分析和測(cè)試之后,才能真正明白這些代碼的意義。上述代碼運(yùn)行結(jié)果如下:

我們已經(jīng)順利獲得了mp4這個(gè)視頻文件地址。根據(jù)視頻地址,使用 urllib.request.urlretrieve() 即可將視頻下載下來(lái)。編寫代碼如下:

urlretrieve()有三個(gè)參數(shù),第一個(gè)url參數(shù)是視頻存放的地址,第二個(gè)參數(shù)filename是保存的文件名,最后一個(gè)是回調(diào)函數(shù),它方便我們查看下載進(jìn)度。代碼量不大,很簡(jiǎn)單,主要在于分析過(guò)程。代碼運(yùn)行結(jié)果如下:

下載速度挺快的,幾分鐘視頻下載好了。

對(duì)于這個(gè)程序,感興趣的朋友可以進(jìn)行擴(kuò)展一下,設(shè)計(jì)出一個(gè)小軟件,根據(jù)用戶提供的url,提供PC在線觀看、手機(jī)在線觀看、視頻下載等功能。

四、總結(jié)

爬蟲(chóng)時(shí)效性低,同樣的思路過(guò)了一個(gè)月,甚至一周可能無(wú)法使用,但是爬取思路都是如此,完全可以自行分析。

本次實(shí)戰(zhàn)代碼,均已上傳我的Github,歡迎Follow、Star:

https://github.com/Jack-Cherish/python-spider

如有問(wèn)題,請(qǐng)留言。如有錯(cuò)誤,還望指正,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評(píng)論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,947評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 175,094評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,485評(píng)論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,268評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 54,817評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,039評(píng)論 0 285
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,551評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,502評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,662評(píng)論 1 366
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,907評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,304評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,563評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,255評(píng)論 3 389
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,637評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容

  • Address:https://www.zybuluo.com/XiangZhou/note/208532 Exp...
    天蠍蒗漫閱讀 11,347評(píng)論 2 55
  • github地址,歡迎大家提交更新。 express() express()用來(lái)創(chuàng)建一個(gè)Express的程序。ex...
    Programmer客棧閱讀 2,555評(píng)論 0 1
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,775評(píng)論 18 139
  • 1 前言 作為一名合格的數(shù)據(jù)分析師,其完整的技術(shù)知識(shí)體系必須貫穿數(shù)據(jù)獲取、數(shù)據(jù)存儲(chǔ)、數(shù)據(jù)提取、數(shù)據(jù)分析、數(shù)據(jù)挖掘、...
    whenif閱讀 18,097評(píng)論 45 523
  • 第一節(jié)MD課程 卜算子·汪 卜算子 我住長(zhǎng)江頭 君住長(zhǎng)江尾夜夜思君不見(jiàn)君 共飲長(zhǎng)江水此水幾時(shí)休 此恨何時(shí)已只愿君...
    bubbley閱讀 464評(píng)論 0 2