urllib爬蟲(流程+案例)


  網絡爬蟲是一種按照一定規則自動抓取萬維網信息的程序。在如今網絡發展,信息爆炸的時代,信息的處理變得尤為重要。而這之前就需要獲取到數據。有關爬蟲的概念可以到網上查看詳細的說明,今天在這里介紹一下使用urllib進行網絡爬蟲的方法使用,在最后的一個案例中把最基本的爬蟲要素運用進去,可以作為初學者的一個模板,讀懂它進行適當修改就可以使用。

  以我的經驗來看,在編程上對於陌生的簡單的東西,最快的學習方法就是從代碼入手了。當然有些很厲害的兄弟,可以完全忽略我這篇博客了。下面的內容我盡量將注釋寫在代碼當中。

1、urllib爬取網頁

  下面是通過urllib的request函數來獲取網頁信息,現在的request庫也很方便,不過原理都是一樣的。

 1 import urllib.request  2 
 3 # 向指定的url地址發送請求並返回服務器響應的數據(文件的對象)
 4 response = urllib.request.urlopen("http://www.baidu.com")  5 
 6 # 讀取文件的全部內容,會把讀到的東西賦值給一個字符串變量
 7 data = response.read()  8 print(data)  # 讀取得到的數據
 9 print(type(data))  # 查看數據類型
10 
11 # 讀取一行
12 data = response.readline() 13 
14 # 讀取文件的全部內容,賦值給一個列表變量,優先選擇
15 data = response.readlines() 16 # print(data)
17 print(type(data[100])) 18 print(type(data[100].decode("utf-8")))  # 轉字符串
19 print(len(data)) 20 
21 # 將爬取到的網頁寫入文件
22 with open(r"F:/python_note/爬蟲/file/file1.html", "wb") as f: 23  f.write(data) 24 
25 
26 # response 屬性
27 
28 # 返回當前環境的有關信息
29 print(response.info()) 30 
31 # 返回狀態碼
32 print(response.getcode()) 33 # 200為正常,304位為有緩存
34 
35 # 返回當前正在爬取的url地址
36 print(response.geturl()) 37 
38 url = "https://www.sogou.com/sgo?query=凱哥學堂&hdq=sogou-wsse-16bda725ae44af3b-0099&lxod=0_16_1_-1_0&lxea=2-1-D-9.0.0.2502-3-CN1307-0-0-2-E96F3D19F4C66A477CE71FD168DD223D-62&lxoq=kaigexuetang&lkx=0&ie=utf8"
39 url2 = r"https%3A//www.sogou.com/sgo%3Fquery%3D%E5%87%AF%E5%93%A5%E5%AD%A6%E5%A0%82%26hdq%3Dsogou-wsse-16bda725ae44af3b-0099%26lxod%3D0_16_1_-1_0%26lxea%3D2-1-D-9.0.0.2502-3-CN1307-0-0-2-E96F3D19F4C66A477CE71FD168DD223D-62%26lxoq%3Dkaigexuetang%26lkx%3D0%26ie%3Dutf8"
40 
41 newurl = urllib.request.quote(url)  # 將含漢字的編碼
42 print(newurl) 43 newurl2 = urllib.request.unquote(url2)  # 解碼
44 print(newurl2) 45 
46 
47 # 端口號,http 80
48 # https 443

2、爬取到的網頁直接寫入文件

  將網頁信息寫入文件可以通過上面的讀取然后再寫入文件,還有更簡便的方法,就是爬取頁面的同時寫入文件,這個也不難,只是一個函數而已。相信應該可以明白下面的內容,filename后面的內容就是需要存儲網頁信息的文件路徑。

1 import urllib.request 2 
3 urllib.request.urlretrieve("http://www.baidu.com", 4                            filename=r"F:/python_note/爬蟲/file/file2.html") 5 
6 # urlretrieve在執行過程中,會產生一些緩存
7 # 清除緩存
8 urllib.request.urlcleanup()

3、模擬瀏覽器

  我們都知道,進行爬蟲的時候,很在乎它的效率,計算機進行獲取數據當然會比手動來的快。但是這樣一來,你就占用了該網站的大部分帶寬,導致其他人上網會很卡。因此,很多網站會有自己的反爬機制,有些只是簡單的預防一下。通過網絡爬蟲進行訪問時會有一個爬蟲的請求頭,那么,可以模擬一下瀏覽器來訪問,也就是把請求頭中的信息換成瀏覽器信息。網上可以找到很多,隨便粘貼一個就好了。

 1 import random  2 import urllib.request  3 
 4 url = "http://www.baidu.com"
 5 
 6 '''
 7 # 模擬請求頭 (這是一種方法,下面使用另一種方法)  8 headers = {  9  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3493.3 Safari/537.36" 10 } 11 # 設置一個請求體 12 req = urllib.request.Request(url, headers=headers) 13 # 發起請求 14 response = urllib.request.urlopen(req) 15 data = response.read() 16 print(data) 17 '''
18 
19 agentsList = [ 20     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60", 21     "Opera/8.0 (Windows NT 5.1; U; en)", 22     "Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50", 23     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50", 24     "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 "
25 ] 26 
27 agentStr = random.choice(agentsList) # 這里是從列表中隨機取出一個瀏覽器信息來改寫請求頭,避免被網站發現同一個地址快速持續的訪問它而被封掉 28 req = urllib.request.Request(url)  # 里面添加頭要寫成鍵值對
29 # 向請求體里添加了User-Agent
30 req.add_header("User-Agent", agentStr)  # 這里添加時傳入兩個字符串,自動組合
31 
32 response = urllib.request.urlopen(req) 33 print(response.read())

4、設置超時

  當訪問一直沒有被響應時,我們需要讓它繼續往下進行而不是卡在那里。通過異常捕獲來實現。

1 import urllib.request 2 
3 # 如果網頁長時間未響應,系統判斷超時,無法爬取
4 for i in range(1, 100): 5     try: 6         response = urllib.request.urlopen("http://www.baidu.com", timeout=0.1) 7         print(len(response.read())) 8     except: 9         print("time out")

5、http請求

  當然有些網站還需要先登錄之類的,也就是不僅僅從上面獲取信息,還需要上傳一些東西,下面介紹一下發送請求的兩種方法。

 1 '''
 2 使用場景:進行客戶端與服務端之間的消息傳遞時使用  3 GET: 通過url網址傳遞信息,可以直接在url網址上添加要傳遞的信息(不安全)  4 POST: 可以向服務器提交數據,是一種比較流行,安全的數據傳遞方式  5 PUT: 請求服務器存儲一個資源,通常要指定存儲的位置  6 DELETE: 請求服務器刪除一個資源  7 HEAD: 請求獲取對應的http報頭信息  8 OPTIONS: 可以獲取當前url所支持的請求類型  9 '''
10 
11 '''
12 get請求: 13 特點:把數據拼接到請求路徑后面傳遞給服務器 14 優點:速度快 15 缺點:承載的數據量小,不安全 16 '''
17 
18 '''
19 post請求: 20 特點:把參數進行打包,單獨傳輸 21 優點:數量大,安全(當對服務器數據進行修改時建議使用post) 22 缺點:速度慢 23 '''
24 import urllib.request 25 import urllib.parse  # 對請求打包的庫
26 
27 url = "http://www.baidu.com"
28 # 將要發送的數據合成一個字典
29 # 字典的鍵去網址里找,一般為input標簽的name屬性的值
30 data = { 31     "username": "xiaoxiao", 32     "passwd": "999"
33 } 34 # 對要發送的數據進行打包
35 postdata = urllib.parse.urlencode(data).encode("utf-8") 36 
37 # 請求體
38 req = urllib.request.Request(url, data=postdata) 39 
40 # 請求
41 response = urllib.request.urlopen(req) 42 print(response.data())

6、json數據解析

 1 '''
 2 概念:一種保存數據的格式  3 作用:可以保存本地的json文件,也可以將json串進行傳輸,通常將json稱為輕量級的傳輸方式  4 xml可讀性更強,但是有很多沒有用的標簽  5 json文件組成:  6 {} 代表對象(字典)  7 [] 代表列表  8 : 代表鍵值對  9 , 分隔兩個部分 10 '''
11 
12 import json 13 
14 # 將json格式的字符串轉換為Python數據類型的對象
15 
16 jsonStr = '{"name":"xiaoxiao", "age":18, "hobby":["money", "power", "english"], "parames":{"a":1, "b":2}}'
17 
18 jsonData = json.loads(jsonStr) 19 print(jsonData) 20 print(type(jsonData)) 21 print(jsonData["hobby"]) 22 
23 
24 jsonData2 = {"name": "xiaoxiao", "age": 18, "hobby": [ 25     "money", "power", "english"], "parames": {"a": 1, "b": 2}} 26 # python類型的數據就是比json格式少個引號
27 
28 # 將Python數據類型的對象轉換為json格式的字符串
29 
30 jsonStr2 = json.dumps(jsonData2) 31 print(jsonStr2) 32 print(type(jsonStr2))

7、抓取網頁動態Ajax請求的數據

  經常瀏覽一些網頁會有這種情況,就是首先加載出一個頁面的內容,向下滾動還有內容,在最下面會有一個提示下拉獲取更多內容這類的東西。這個可以讓加載網頁的速度更快,畢竟內容少了嘛,再我們想要看到更多信息時候再加載。對於這樣的一部分頁面爬取其實也很簡單,細心觀察一下每次多加載一塊的頁面時,這時候上方的網址變化可以發現,有些是有數字變化的。可以根據里面的具體規律來修改每次請求的信息。

 1 import urllib.request  2 import ssl  3 import json  4 
 5 
 6 def ajaxCrawler(url):  7     headers = {  8         "User-Agent": "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10"
 9  } 10     req = urllib.request.Request(url, headers=headers) 11 
12     # 使用ssl創建未驗證的上下文
13     context = ssl._create_unverified_context()  # 訪問的是HTTPS
14 
15     response = urllib.request.urlopen(req, context=context) 16     jsonStr = response.read().decode("utf-8") 17     print(type(response.read()))  # byte型
18     print(type(response.read().decode("utf-8")))  # json字符串型
19     jsonData = json.loads(jsonStr) 20     return jsonData 21 
22 
23 # url = "https://movie.douban.com/j/chart/top_list?type=17&interval_id=100%3A90&action=&start=0&limit=20"
24 # info = ajaxCrawler(url)
25 # print(info)
26 
27 for i in range(1, 11): 28     url = "https://movie.douban.com/j/chart/top_list?type=17&interval_id=100%3A90&action=&start=" + \ 29         str(i * 20) + "&limit=20"
30     info = ajaxCrawler(url) 31     print(len(info))

8、糗事百科爬蟲

 1 import urllib.request  2 import re  3 
 4 # https://www.qiushibaike.com/text/page/2/
 5 
 6 
 7 def jokeCrawler(url):  8     headers = {  9         "User-Agent": "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10"
10  } 11     req = urllib.request.Request(url, headers=headers) 12     response = urllib.request.urlopen(req) 13 
14     html = response.read().decode("utf-8") 15     # print(type(html))
16 
17     pat = r'<div class="author clearfix">(.*?)<span class="stats-vote"><i class="number">'
18     re_joke = re.compile(pat, re.S)  # re.S 使可以匹配換行
19     divsList = re_joke.findall(html) 20     # print(divsList)
21     # print(len(divsList))
22 
23     dic = {} 24     for div in divsList: 25         # 用戶名
26         re_u = re.compile(r"<h2>(.*?)</h2>", re.S) 27         username = re_u.findall(div) 28         username = username[0].rstrip() 29         # print(username)
30         # 段子
31         re_d = re.compile(r'<div class="content">\n<span>(.*?)</span>', re.S) 32         duanzi = re_d.findall(div) 33         duanzi = duanzi[0].strip() 34         # print(type(duanzi))
35         dic[username] = duanzi 36     return dic 37 
38     # with open(r"F:/python_note/爬蟲/file/file2.html", "w") as f:
39     # f.write(html)
40 
41 
42 url = "https://www.qiushibaike.com/text/page/1/"
43 info = jokeCrawler(url) 44 for k, v in info.items(): 45     print(k + ':\n' + v)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM