手把手教你學python第十八講(初識爬蟲)

NO IMAGE

圖片出不來請到https://www.bilibili.com/read/cv341382?from=category_17

學習爬蟲呢?我們首先要知道什麼叫做爬蟲,爬蟲其實又叫做網頁蜘蛛。網際網路就是一個大的蜘蛛網,而網頁蜘蛛在網上爬來爬去的行為就是我們不斷閱讀網頁的行為。

那麼下面就有問題了啊,我們以前完全沒有講過python如何訪問網際網路啊。python怎麼訪問網際網路呢?就是通過下面的模組。

urllib是url和lib(庫)組成。先看一下urllib是個什麼東西

看到urllib是一個包,裡面有五個模組。我們再實際去看一下

然後我們來說一說URL是什麼。知己知彼才能更好的應用爬蟲嘛,參考了百度百科。

URL

百度百科是把後面兩部分作為一部分。

下面參考了https://jingyan.baidu.com/article/2c8c281df0afd00008252aa7.html,我認為說的很詳細,就直接拿過來了,不想自己在重新組織語言了,人的惰性所致。

我們先了解一下什麼叫伺服器

我們上面說的都是WEB伺服器,下面說的也是。其實伺服器就是一臺大型計算機嘛。

也就是說一個域名可以有不同的網站名,因為伺服器可以不一樣。

我來重複一遍,第一個是我們打進去的,第二個是電腦自動給我們加的,第三個是伺服器自動加的根目錄,前面我們在檔案系統那裡講過根目錄的概念。最後一個是根目錄下預設的網頁。

前面的協議名字不同的網站可能會不一樣,現在一般都是https,這樣的沒有彈窗啊,廣告什麼的。上面我是寫了80埠,下面換一個81號埠試試,你問我什麼叫做埠(port)?這個我還是知道的,畢竟學過微機原理,首先,計算機與外設通訊的電路叫做介面,埠就是介面裡面的暫存器,通常有控制,狀態,資料埠。你的計算機上有各種介面,典型的有USB介面,顯示卡介面,鍵盤介面等。計算機給每個埠都有一個二進位制或者說十六進位制的地址,多少位和你的地址匯流排寬度有關係哈。這裡面還有一個獨立編址還是統一編址的問題,不過你只需要知道一個埠有唯一的地址就夠了。我就知道這些,我們也就到這就夠了。

如果你知道了伺服器就是一臺大型計算機,那麼絕對URL和相對URL你就理解了,和絕對路徑相對路徑類似嘛。

除了URL還有一個東西叫做URI,這些以後都會用到的,參考了https://www.zhihu.com/question/21950864

詳細來說呢,我覺得知乎這位寫得很形象,我就不獻醜了。

URI就是一種一一對應對應關係的某種識別符號,這個可以有很多種,區別一個人,我們可以用,身份證號,手機號,QQ號,郵箱(一個人可以有多個手機號,同樣的,一個網站可以有多個URL的,不過那樣就太分散了,但是絕對不會有兩個不同的網站有一樣的URL),住址,等等。URL是什麼呢?就是其中的一種類似於住址的定位符,比如說你住在哪個寢室幾號床啊,有人可能會說,我和我爸睡在一個屋子裡的一張床上,那這個顯然是擡槓,不過這個例子確實不是很嚴謹,但是還是可以幫助我們理解的。

稍微擴充套件一下知識

有了以上知識,到實際中操作一下吧。如何開啟一個網頁?urllib包裡的request模組有urlopen函式

爬蟲初試

這個階段我們只用到了第一個引數URL。

試著來開啟一個網頁,比如流氓的百度

看來目前開啟一個網頁需要,把協議名和網站名都輸進去,而且輸埠號會報錯,報錯說是違反了協議,這個去到原始檔應該是可以看到為什麼報錯的,這裡我就不展示了,有興趣自己可以根據報錯內容,自己去相關的模組的原始檔看一看。返回的是一個http.client模組的HTTPResponse物件。先簡單瞭解一下http.client模組,參考了http://www.jb51.net/article/109852.htm。寫的真的不錯,我覺得這種可以直接拿來用的,我就不自己獻醜寫了。

看到這個443埠是不是上面的報錯就豁然開朗了呢?唉,原來是埠不對造成的嘛,當然如果你想深究的話,沒有這麼簡單,你需去ssl.py的握手handshake這一行去找原因。

還有

有興趣的可以自己深入瞭解。其實理解起來很簡單,就是不是預設埠訪問不到唄。

並且在responses裡我們 可以看到熟悉的404。

我們就偏要來試試例項化這個HTTPResponse類。

這個錯誤原因要究其根源就要扯太多了,不是僅僅缺了sock引數這麼簡單,而且要讀很多行程式碼,費時間而且大家也不一定能讀懂,所以大家自己有經驗有耐心的時候再去讀更好,讀高手的程式碼也是進步的一個很重要的方法哦。下面我就只擷取了和HTTPResponse有關的內容,其它的你們可以自己開啟那個網站看,如果你有興趣的話。其實這些以後都會講到,只是現在還沒到時候。

注意紅箭頭的read我們下面馬上會用得到。

這裡就再科普幾個知識吧。下面我都儘量選通俗的解釋。先說一下什麼叫做DNS

以下參考了https://blog.csdn.net/paranoidyang/article/details/54288370

DNS就是把域名轉換為IP地址。

閘道器。

子網掩碼,參考了https://www.zhihu.com/question/56895036

所以通過子網掩碼我們可以推算出每個兒子內網的範圍咯。回過來繼續看。

對了這裡還漏了一點內容,HTTPResponse返回的是一個二進位制的物件,因為計算機只認識0,1在網路傳輸的過程中自然也必須只能傳送二進位制了。上面也說過read可以讀取返回的HTTPResponse的內容,我們來試一試,讀一個簡單點的吧,就讀取b站主頁的前1000個位元組吧,,不然會很長很長,

這讀出來是二進位制嗎?你看到開頭有個b,還有很多\x十六進位制的數字。沒錯,這的確是二進位制檔案(雖然看著不全是二進位制的數,還有一些拉丁字母和英文標點,下面會講解為什麼是這樣的,實際上缺失的都是不能用ASCII碼錶示的字元)。這裡就有必要詳細瞭解編碼的一些知識

編碼[encode]和譯碼(解碼)[decode]

參考了http://bbs.fishc.com/thread-66084-1-1.html和https://www.cnblogs.com/OldJack/p/6658779.html

還有http://python.jobbole.com/86670/和https://www.cnblogs.com/vipchenwei/p/6993788.html

unicode就是universal code的意思。GBK就比較中式,叫國標擴充套件,接觸過機械的都見過GB/什麼什麼的,那就是國標的首字母。

下面是更清晰地說明UTF-8是如何儲存Unicode碼的https://blog.csdn.net/hezh1994/article/details/78899683。還有http://www.cnblogs.com/yyds/p/6171340.html

UTF的全稱是Unicode transformation format。

更詳細點

編碼問題是很重要的問題。我就再總結一下編碼,如果學過數位電子就更好理解了,比如說2用8421碼來編就是10,用格雷碼來編就是11,編碼就是把我們認識的字元都轉化為計算機認識的0和1。為了把英文字元一一對應為電腦認識的二進位制,美國人發明了ASCII碼,為了把中文字元一一對應為二進位制,我們中國有現在一般是GBK碼,同樣日本,韓國等都有自己國家的語言對應到二進位制的碼,而且會出現同一個二進位制在不同國家的編碼體系裡對應不同的字元,這也很好理解對吧。這樣不便於大家交流,那麼就需要有統一的一種編碼方式了,然後Unicode就誕生了,它這種體系可以包容各個國家的語言,可以保證每個二進位制數和字元的一一對應關係,不會出現比如說某個二進位制既對應著中國的‘你‘,又對應著美國的’fuck’。但是Unicode的碼儲存起來是很耗費空間的,這時候就需要用到utf這種變位元組儲存方式來存,utf-8是我們比較常用的。那麼譯碼就是反過程咯。我們可以在命令列裡檢視系統的預設編碼,右鍵標題欄,點屬性

可以看到是GBK的。你也可以在命令列直接輸入chcp就可以檢視。如果是936那麼就也是GBK編碼。也可以檢視python預設的編碼方式是什麼樣的。

我們再來深入探索一下編碼與解碼的世界。參考了https://www.cnblogs.com/abclife/p/7445222.html和https://www.cnblogs.com/654321cc/p/7419124.html。

bin是把一個整數轉換為二進位制,用的是8421碼,並且只能轉換整數。我們一般用不到它,因為你在鍵盤上面敲進去的數字也全是字元,並不是數字。什麼意思呢?還記得input嗎?

只有經過了int才轉化成整數了。這就是我們輸入的都是字元的含義。以前我們曾經用過ord()說它返回的是ASCII碼,其實是不對的,返回的是utf-8碼,只是因為拉丁字母和一些特殊字元的ASCII碼和UTF—8碼是一樣的或者說是相容的而已。返回的是單個字元的utf-8碼

當然實際存在計算機裡都是二進位制的,只是為了方便使用者看,顯示出來的是十進位制的。與之對應的是chr

為什麼chr(23)和chr(31)沒有顯示字元呢?因為ASCII碼錶裡(我為什麼用ASCII碼錶呢?因為utf-8和ASCII碼是相容的),23和31對應的字元都是控制字元,python並不能給你顯示出來,所以返回了一個十六進位制字元。

Bytes()前面也說到是一種二進位制型別。

列印出來的 格式預設都是十進位制。

字串內部確實有encode()編碼的內建函式可以按照給定編碼形式把字串進行編碼,轉換為二進位制的形式,如果不給編碼形式那麼就按照python預設的utf-8來編碼。bytes類的內建方法decode()可以按照給定解碼方式解碼,如果不給就按照python預設的utf-8解碼。上面d為什麼按照utf-8解碼錯誤呢?因為回去看這個表

\xd6\xd0二進位制就是11010110  11010000,這樣的二進位制是不符合utf-8的格式的。有的時候不會報錯,但是會出現亂碼。還有可能會出現下面的情況。

為什麼有的返回的不是b十六進位制而是直接b 原來的字串呢?根據上面的嘗試我猜想是ASCII碼裡有的列印字元在後來的所有編碼格式裡包括GBK,utf-8等等裡面都是直接繼承了ASCII碼的。因為大家都一樣嘛,所以就直接前面加個b表示這是二進位制就返回了。到這裡,你就知道前面b站主頁返回的前1000個位元組為什麼有的是\x十六進位制,有的直接就是拉丁字母和英文標點了。

下面看看bytes()的作用。

其實就是編碼,而且後面還必須要加上編碼的格式。並且上面驗證了所有編碼格式都繼承了美國最早的ASCII碼的所有拉丁字母和英文字元的對應關係。這樣就理解了為什麼上面獲取的網站後返回的HTTPResponse型別為什麼不全是\x的十六進位制形式,可以看到拉丁字母和英文字元都是直接表示出來了,因為在python認可的所有編碼體系裡它們的二進位制都一樣,不需要給出來了。有時候我們開啟的檔案會出現亂碼,是怎麼回事呢?下面我們要學習一下python裡的檔案讀取操作,

python之檔案讀取簡單原理

參考了http://www.cnblogs.com/yyds/p/6186621.html和

http://www.cnblogs.com/yyds/p/6171340.html

首先我們要明白一個概念,磁碟寫入或讀取資料時使用的字元編碼是由編輯器指定的工程或檔案的字元編碼決定的,這與Python解釋是無關的。Python3的直譯器以”UTF-8″作為預設編碼,但是這並不表示可以完全相容中文問題。比如我們在Windows上進行開發時,Python工程及程式碼檔案都使用的是預設的GBK編碼,也就是說Python程式碼檔案是被轉換成GBK格式的位元組碼儲存到磁碟中的。怎麼體現這點呢?

首先我們寫了一個txt檔案,這個檔案是怎麼被寫進去的?還是必須先編碼才行,由於我們沒有指定編碼方式,就用了預設的GBK,因為計算機只認識0和1,然後這個編碼方式其實也傳給了計算機,那麼我們的計算機就會以GBK的格式去解碼傳過來的二進位制資料,也就是編碼解碼方式是一樣的,我們才能看到’中文‘。那麼我們就試試用‘utf-8’去編碼試一下咯。

我們還是看到了正常的’中文’,這前面說過是因為編碼方式也被傳遞給計算機了,計算機會按照python傳過來的編碼格式也就是utf-8來解碼。但是當python在讀取的時候,它是得不到這個我們原來傳過去的編碼方式的,它得到的就只有文字內容的一堆二進位制,如何解碼呢?不知道,我們如果不給它解碼方式,它就按照預設的GBK來解碼,結果就報錯了。你們可以自己去對照GBK的表http://www.qqxiuzi.cn/zh/hanzi-gbk-bianma.php。然後我們來看

我們先來了解什麼叫做流,參考了https://www.zhihu.com/question/38075755,https://blog.csdn.net/hansnowqiang/article/details/50130437和https://blog.csdn.net/u011000290/article/details/48940371。

當然上面只是說了我們為什麼需要緩衝區的原因,還沒有說什麼是流。

我們不再延伸了,有興趣可以自己去學有關流的更多操作。

API就是Application Programming Interface,應用程式程式設計介面,就是前人已經寫好的實現複雜功能的函式,以供後人可以直接呼叫。

上面編碼花了好打空間,我們回過來繼續學爬蟲,上面這些後面課程的基礎,所以我在爬蟲的第一講先講一部分知識,當然這還沒有包含掌握爬蟲需要掌握的所有知識。以後再慢慢滲透吧。前面爬取b站的時候,我們得到的是編碼過的二進位制,需要譯碼成我們可以看懂的形式。譯碼之前我們就需要知道百度是什麼編碼方式,怎麼獲得呢?其實很簡單按F12就可以審查元素了。這個Elements裡面是HTML程式碼,

Console裡面是除錯JavaScipt的,Sources是資源,後面的暫時後用不到。然後點開head,charset後面就是編碼的格式。

知道了編碼形式我們來解碼吧。

你可以去和上面對比,哪些是十六進位制的地方絕對都是漢字。雖然還是看不懂HTML,但是這並不妨礙你找資源。這裡在稍微說一個小知識

再寫十六進位制的時候,你需要按照位元組來寫\x號,什麼意思呢?對比下面你就懂了

第一種寫法b’\x8140’其實是\x81=129,ord(‘4’)=52,ord(‘0’)=48。第二種才是\x81=128,\x40=64。

下面就先來大展一番身手吧

練習

0.編寫一段程式,檢測指定URL的編碼。

1.寫一個程式,依次訪問指定資料夾裡的網頁,並將內容儲存在不同的檔案中。

答案和講解會在下一講公佈。