2020年9月12日星期六

52 《零基礎入門學習Python》筆記 第053講:論一隻爬蟲的自我修養

《零基礎入門學習Python》筆記    第053講:論一隻爬蟲的自我修養


目錄
0. 請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!
測試題
0. 請問URL 是“統一資源標識符”還是“統一資源定位符”?
1. 什麼是爬蟲?
2. 設想一下,如果你是負責開發百度蜘蛛的攻城獅,你在設計爬蟲時應該特別注意什麼問題?
3. 設想一下,如果你是網站的開發者,你應該如何禁止百度爬蟲訪問你網站中的敏感內容?
4. urllib.request.urlopen() 返回的是什麼類型的數據?
5. 如果訪問的網址不存在,會產生哪類異常?
6. 魚C工作室(https://ilovefishc.com)的主頁採用什麼編碼傳輸的?
7. 為了解決ASCII 編碼的不足,什麼編碼應運而生?
動動手
0. 下載魚C工作室首頁(https://ilovefishc.com),並打印前三百個字節。
1. 寫一個程序,檢測指定URL 的編碼。
2. 寫一個程序,依次訪問文件中指定的站點,並將每個站點返回的內容依次存放到不同的文件中。

0. 請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!

馬上我們的教學就要進入最後一個章節,Pygame 嗨爆引爆全場,但由於發生了一個小插曲,所以這裡決定追加一個章節,因為有人反應說:“你上一節課教我們去查找文檔,教我們如何從官方文檔中找到需要的答案,但是我發現知易行難也,希望舉一個詳細點的例子,教我們如何去查找。”
所以這裡我們詳細的深刻的講一下網絡爬蟲所以就有了本章節,論一隻爬蟲的自我修養。
首先,我們需要理解,什麼是網絡爬蟲,如圖:
網絡爬蟲又稱為網絡蜘蛛(Spider),如果你把整個互聯網想像為一個蜘蛛網的構造,每個網站或域名都是一個節點,那我們這只蜘蛛就是在上面爬來爬去,在不同的網頁上爬來爬去,順便獲得我們需要的資源,抓取最有用的。做過網站的朋友一定很熟悉,我們之所以能夠通過百度、谷歌這樣的搜索引擎檢索到你的網頁,靠的就是他們每天派出大量的蜘蛛在互聯網上爬來爬去,對網頁中的每個關鍵字建立索引,然後建立索引數據庫,經過了複雜的排序算法之後,這些結果將按照搜索關鍵詞的相關度的高低展現在我們的眼前。那當然,現在讓你編寫一個搜索引擎是一件非常苦難的、不可能完成的事情,但是有一句老話說的好啊:千里之行,始於足下。我們先從編寫一段小爬蟲代碼開始,然後不斷地來改進它,要使用Python編寫爬蟲代碼,我們要解決的第一個問題是:
Python如何訪問互聯網?
好在Python為此準備好了電池,Python為此準備的電池叫做:urllib
urllib 事實上是由兩個單詞組成的:URL(就是我們平時說的網頁地址) 和lib(就是library的意思,就是首頁)。
•URL的一般格式為(帶方括號[]的為可選項):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
•URL由三部分組成:
–第一部分是協議(protocol):http,https,ftp,file,ed2k…
–第二部分是存放資源的服務器的域名系統或IP地址(有時候要包含端口號,各種傳輸協議都有默認的端口號,如http的默認端口為80)。
–第三部分是資源的具體地址,如目錄或文件名等。
那好,說完URL,我們現在可以來談一下urllib 這個模塊了,Python 3 其實對這個模塊進行了挺大的改動,以前有urllib和urllib2 兩個模塊,Python3 乾脆把它們合併在了一起並做了統一。其實urllib 並不是一個模塊,而是一個包。我們來查一下文檔就知道了(我們說過,有問題,找文檔。)
urllib 其實是一個包,其中包含4個模塊,request 、error、parse 和robotparser,我們主要會來講解request 這個模塊,這個模塊也是最複雜的,因為它包含了對服務器的請求和發出、跳轉、代理、安全等幾大方面。
我們點進去會發現文檔非常長,從頭看到尾是不可能的,這時候怎麼辦呢?建議百度、谷歌,查詢urllib.request 的用法,或者查詢Python3 如何訪問網頁,也可以得到想要的結果。你會得到,使用urlopen() 這個函數。
urlopen()函數除了第一個參數url是必需的外,後面的都有默認參數和可選參數,文檔告訴我們,url可以是一個字符串或者Request objectRequest object是什麼,我們下節課講解。我們猜測url為一個字符串是應該就是域名地址的字符串,我們先來嘗個鮮:(之所以選擇https://ilovefishc.com這個網頁,是因為這個網頁的源代碼量較少,其他的網站會直接把IELD搞崩潰,不信你可以試試https://www.baidu.com。)
  1. >>> import urllib.request
  2. >>> response = urllib.request.urlopen("https://ilovefishc.com")
  3. >>> html = response.read()
  4. >>> print(html)
  5. b'<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <meta name="keywords" content="\xe9\xb1\xbcC\xe5\xb7\xa5\xe4\xbd\x9c\xe5\xae\xa4|\xe5\x85\x8d\xe8\xb4\xb9\xe7\xbc\x96\xe7\xa8\x8b\xe8\xa7\x86\xe9\xa2\x91\xe6\x95\x99\xe5\xad\xa6|Python\xe6\x95\x99\xe5\xad\xa6|Web\xe5\xbc\x80\xe5\x8f\x91\xe6\x95\x99\xe5\xad\xa6|\xe5\x85\xa8\xe6\xa0\x88\xe5\xbc\x80\xe5\x8f\x91\xe6\x95\x99\xe5\xad\xa6|C\xe8\xaf\xad\xe8\xa8\x80\xe6\x95\x99\xe5\xad\xa6|\xe6\xb1\x87\xe7\xbc\x96\xe6\x95\x99\xe5\xad\xa6|Win32\xe5\xbc\x80\xe5\x8f\x91|\xe5\x8a\xa0\xe5\xaf\x86\xe4\xb8\x8e\xe8\xa7\xa3\xe5\xaf\x86|Linux\xe6\x95\x99\xe5\xad\xa6">\n <meta name="description" content="\xe9\xb1\xbcC\xe5\xb7\xa5\xe4\xbd\x9c\xe5\xae\xa4\xe4\xb8\xba\xe5\xa4\xa7\xe5\xae\xb6\xe6\x8f\x90\xe4\xbe\x9b\xe6\x9c\x80\xe6\x9c\x89\xe8\xb6\xa3\xe7\x9a\x84\xe7\xbc\x96\xe7\xa8\x8b\xe8\xa7\x86\xe9\xa2\x91\xe6\x95\x99\xe5\xad\xa6\xe3\x80\x82">\n <meta name="author" content="\xe9\xb1\xbcC\xe5\xb7\xa5\xe4\xbd\x9c\xe5\xae\xa4">\n <title>\xe9\xb1\xbcC\xe5\xb7\xa5\xe4\xbd\x9c\xe5\xae\xa4-\xe5\x85\x8d\xe8\xb4\xb9\xe7\xbc\x96\xe7\xa8\x8b\xe8\xa7\x86\xe9\xa2\x91\xe6\x95\x99\xe5\xad\xa6|Python\xe6\x95\x99\xe5\xad\xa6|Web\xe5\xbc\x80\xe5\x8f\x91\xe6\x95\x99\xe5\xad\xa6|\xe5\x85\xa8\xe6\xa0\x88\xe5\xbc\x80\xe5\x8f\x91\xe6\x95\x99\xe5\xad\xa6|C\xe8\xaf\xad\xe8\xa8\x80\xe6\x95\x99\xe5\xad\xa6|\xe6\xb1\x87\xe7\xbc\x96\xe6\x95\x99\xe5\xad\xa6|Win32\xe5\xbc\x80\xe5\x8f\x91|\xe5\x8a\xa0\xe5\xaf\x86\xe4\xb8\x8e\xe8\xa7\xa3\xe5\xaf\x86|Linux\xe6\x95\x99\xe5\xad\xa6</title>\n <link rel="shortcut icon" type="image/x-icon" href="img/favicon.ico">\n <link rel="stylesheet" href="css/styles.css">\n <script src="js/jq.js"></script>\n <script src="https://cdn.bootcss.com/timelinejs/2.36.0/js/storyjs-embed.js"></script>\n <script src="https://cdnjs.cloudflare.com/ajax/libs/timelinejs/2.36.0/js/storyjs-embed.js" defer></script>\n <!-- <script src="https://fishc.oss-cn-hangzhou.aliyuncs.com/Web/js/embed.js"></script> -->\n <script>\n $(document).ready(function() {\n var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;\n\n createStoryJS({\n type: \'timeline\',\n width: \'auto\',\n height: windowHeight,\n source: \'data.json\',\n start_at_end:true, //OPTIONAL START AT LATEST DATE\n embed_id: \'my-timeline\'\n });\n\n });\n </script>\n <!-- END TimelineJS -->\n</head>\n<body>\n<div id="my-timeline"></div>\n</body>\n</html>\n'
得到的字符串是一個以b 開頭(二進制)字符串。得到的字符串似乎和我們所理解的網頁代碼不一樣,但是我們又看到了很熟悉的身影(例如:div,link rel等),但是在這個網頁,如果右鍵審查元素
我們會發現網頁的代碼很整齊,那這是怎麼回事呢?為什麼Python這里高的一團糟,我們剛才說了,Python這裡直接得到的是byte類型(二進制編碼),所以我們可以對它進行解碼操作,我們先來看一下這個網頁的編碼方式是:UTF-8。
  1. >>> html = html.decode("utf-8")
  2. >>> print(html)
  3. <!DOCTYPE html>
  4. <html lang="en">
  5. <head>
  6. <meta charset="UTF-8">
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  8. <meta name="keywords" content="鱼C工作室|免费编程视频教学|Python教学|Web开发教学|全栈开发教学|C语言教学|汇编教学|Win32开发|加密与解密|Linux教学">
  9. <meta name="description" content="鱼C工作室为大家提供最有趣的编程视频教学。">
  10. <meta name="author" content="鱼C工作室">
  11. <title>鱼C工作室-免费编程视频教学|Python教学|Web开发教学|全栈开发教学|C语言教学|汇编教学|Win32开发|加密与解密|Linux教学</title>
  12. <link rel="shortcut icon" type="image/x-icon" href="img/favicon.ico">
  13. <link rel="stylesheet" href="css/styles.css">
  14. <script src="js/jq.js"></script>
  15. <script src="https://cdn.bootcss.com/timelinejs/2.36.0/js/storyjs-embed.js"></script>
  16. <script src="https://cdnjs.cloudflare.com/ajax/libs/timelinejs/2.36.0/js/storyjs-embed.js" defer></script>
  17. <!-- <script src="https://fishc.oss-cn-hangzhou.aliyuncs.com/Web/js/embed.js"></script> -->
  18. <script>
  19. $(document).ready(function() {
  20. var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
  21. createStoryJS({
  22. type: 'timeline',
  23. width: 'auto',
  24. height: windowHeight,
  25. source: 'data.json',
  26. start_at_end:true, //OPTIONAL START AT LATEST DATE
  27. embed_id: 'my-timeline'
  28. });
  29. });
  30. </script>
  31. <!-- END TimelineJS -->
  32. </head>
  33. <body>
  34. <div id="my-timeline"></div>
  35. </body>
  36. </html>

測試題


0. 請問URL 是“統一資源標識符”還是“統一資源定位符”?

答:往後的學習你可能會經常接觸URL 和URI,為了防止你突然懵倒,所以在這裡給大家簡單普及下。URI 是統一資源標識符(Universal Resource Identifier),URL 是統一資源定位符(Universal Resource Locator)。用一句話概括它們的區別:URI 是用字符串來標識某一互聯網資源,而URL 則是表示資源的地址(我們說某個網站的網址就是URL),因此URI 屬於父類,而URL 屬於URI的子類。


1. 什麼是爬蟲?

答:爬蟲事實上就是一個程序,用於沿著互聯網結點爬行,不斷訪問不同的網站,以便獲取它所需要的資源。


2. 設想一下,如果你是負責開發百度蜘蛛的攻城獅,你在設計爬蟲時應該特別注意什麼問題?

答:不要重複爬取同一個URL 的內容。假設你沒做這方面的預防,如果一個URL 的內容中包含該URL 本身,那麼就會陷入無限遞歸。


3. 設想一下,如果你是網站的開發者,你應該如何禁止百度爬蟲訪問你網站中的敏感內容?

(課堂上沒講,可以自行百度答案)
答:在網站的根目錄下創建並編輯robots.txt 文件,用於表明您不希望搜索引擎抓取工具訪問您網站上的哪些內容。此文件使用的是Robots 排除標準,該標準是一項協議,所有正規搜索引擎的蜘蛛均會遵循該協議爬取。既然是協議,那就是需要大家自覺尊重,所以該協議一般對非法爬蟲無效。


4. urllib.request.urlopen() 返回的是什麼類型的數據?

答:返回的是一個HTTPResponse的實例對象,它屬於http.client模塊。
  1. >>> response = urllib.request.urlopen("http://www.fishc.com")
  2. >>> type(response)
  3. <class 'http.client.HTTPResponse'>
調用其read()方法才能讀出URL的內容。


5. 如果訪問的網址不存在,會產生哪類異常?

(雖然課堂沒講過,但你可以動手試試)
答:HTTPError


6.魚C工作室(https://ilovefishc.com )的主頁採用什麼編碼傳輸的?

答:UTF-8 編碼。
一般網頁通過點擊審查元素,在<head> 標籤中的charset 會顯示採用了哪種編碼。


7. 為了解決ASCII 編碼的不足,什麼編碼應運而生?

答:Unicode編碼。擴展閱讀關於編碼的那篇文章太長了,有魚油說太生澀難懂,對於對編碼問題還一頭霧水的魚油請看->  什麼是編碼?

動動手


0.下載魚C工作室首頁(https://ilovefishc.com ),並打印前三百個字節。

代碼清單:
  1. >>> import urllib.request
  2. >>> response = urllib.request.urlopen('http://www.fishc.com')
  3. >>> print(response.read(300))
  4. b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\r\n\t"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r\n\r\n<!-- \r\n(c) 2011 \xc4\xbdubom\xc3\xadr Krupa, CC BY-ND 3.0\r\n -->\t\r\n\r\n<html xmlns="http://www.w3.org/1999/xhtml">\r\n\t<head>\r\n\t\t<meta http-equiv="content-type" content="text/html; charset=utf-8" />\r\n\t\t'


1. 寫一個程序,檢測指定URL 的編碼。

演示:
提示:
提供個“電池”給你用->  一次性解決你所有的編碼檢測問題
代碼清單:
  1. import urllib.request
  2. import chardet
  3. def main():
  4. url = input("请输入URL:")
  5. response = urllib.request.urlopen(url)
  6. html = response.read()
  7. # 识别网页编码
  8. encode = chardet.detect(html)['encoding']
  9. if encode == 'GB2312':
  10. encode = 'GBK'
  11. print("该网页使用的编码是:%s" % encode)
  12. if __name__ == "__main__":
  13. main()


2. 寫一個程序,依次訪問文件中指定的站點,並將每個站點返回的內容依次存放到不同的文件中。

演示:
urls.txt 文件存放需要訪問的ULR:
執行你寫的程序(test.py),依次訪問指定的URL 並將其內容存放為一個新的文件:
代碼清單:
  1. import urllib.request
  2. import chardet
  3. def main():
  4. i = 0
  5. with open("urls.txt", "r") as f:
  6. # 读取待访问的网址
  7. # 由于urls.txt每一行一个URL
  8. # 所以按换行符'\n'分割
  9. urls = f.read().splitlines()
  10. for each_url in urls:
  11. response = urllib.request.urlopen(each_url)
  12. html = response.read()
  13. # 识别网页编码
  14. encode = chardet.detect(html)['encoding']
  15. if encode == 'GB2312':
  16. encode = 'GBK'
  17. i += 1
  18. filename = "url_%d.txt" % i
  19. with open(filename, "w", encoding=encode) as each_file:
  20. each_file.write(html.decode(encode, "ignore"))
  21. if __name__ == "__main__":
  22. main()

0 留言:

發佈留言