网络爬虫(一)——爬虫及其实现
文章目錄
- 1.1 爬蟲概述
- 1.1.3 網絡爬蟲和瀏覽器的區別
- 1.1.2 網絡爬蟲的定義
- 1.2 requests請求庫
- 1.2.1 requests基本概念
- 1.2.2 疫情數據爬取
- 1.2.3 get請求
- 1.2.4 headers請求頭
- 1.2.5 Cookies驗證
- 1.3 Beautiful Soup解析庫
- 1.3.1 安裝
- 1.3.2 對象的創建
- 1.3.3 find方法
- 1.3.4 后話
- 1.4 正則表達式
- 1.4.1 正則表達式語法
- 1.4.2 re.findall()方法
- 1.4.3 r原串的使用
- 1.4.4 案例
- 1.5 json
- 1.5.1 json模塊
- 1.5.2 python轉json
- 1.5.3 案例
1.1 爬蟲概述
1.1.3 網絡爬蟲和瀏覽器的區別
瀏覽器和爬蟲都是在訪問網站的服務器,然后返回對應的數據。不同的是,瀏覽器返回的數據還會經過渲染,變成十分美觀的界面。而對于爬蟲來說,返回的一般是原生的HTML代碼。
1.1.2 網絡爬蟲的定義
網絡爬蟲也叫網絡蜘蛛或網絡機器人,其模擬客戶端發送網絡請求,獲取響應數據。換而言之,它是一種按照一定的規則,自動抓取萬維網信息的程序或腳本。
1.2 requests請求庫
1.2.1 requests基本概念
requests是一個優雅而簡單的pythonHTTP請求庫。它的作用是發送請求獲取響應數據。如果你想要安裝這個庫,可以打開anaconda3的prompt黑窗口,然后在對應的環境中輸入
pip install requests
安裝完成后,我們來試著返回一下百度搜索的源代碼
# 導入模塊 import requests# 發送請求,獲取響應 response = requests.get("https://www.baidu.com/")# 獲取響應數據 response.encoding = 'utf8' print(response.text)從以上的演示來看,我們可以從中總結requests使用的步驟:
- 導入模塊
- 發送get請求,獲取響應
- 從響應中獲取數據
這里還要給大家科普response對象的方法。
response.text:響應體str類型
response.ecoding:二進制轉換字符使用的編碼
response.content:響應體bytes類型
1.2.2 疫情數據爬取
我們來試著爬取一下丁香園新型冠狀病毒疫情實時動態首頁內容。其url為:全球新冠肺炎疫情地圖 - 丁香園·丁香醫生 (dxy.cn)
# 導入模塊 import requests# 發送請求,獲取響應對象 response = requests.get("http://ncov.dxy.cn/ncovh5/view/pneumonia")# 從響應對象中獲取數據 print(response.content.decode()) #print(response.text)1.2.3 get請求
對于get請求返回的響應對象,實際上含有多種方法可調用。
- response.url:打印請求url
- response.headers:打印請求頭
- response.cookies:打印cookie信息
- response.status_code:打印請求狀態碼
對于狀態碼來說,有如下幾種情況:
1.2.4 headers請求頭
對于某些網頁,其實現了反爬機制,所有通過get方法無法獲取數據。這時候我們可以模擬瀏覽器的頭部信息來訪問。
每個瀏覽器的頭部信息不同。如何查看瀏覽器的頭部信息呢?
打開一個網頁,點檢查,然后刷新一下網頁,然后按照上圖操作即可找到頭部信息。
在使用get請求時,只需在get方法的有參構造中傳入對應的請求頭即可。如下所示:
import requests# 瀏覽器頭部信息 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36 Edg/100.0.1185.29'} url = "http://ncov.dxy.cn/ncovh5/view/pneumonia"response = requests.get(url, headers=headers) print(response.status_code)1.2.5 Cookies驗證
在爬取某些數據時,需要進行網頁的登錄,才可以進行數據的抓取工作。Cookies登錄就像很多網頁中的自動登錄功能一樣,可以讓用戶第二次登錄時在不需要驗證賬號和密碼的情況下進行登錄。在使用requests模塊實現Cookies登錄時,首先需要在瀏覽器的開發者工具頁面中找到可以實現登錄的Cookies信息,然后將Cookies信息處理并添加至RequestsCookieJar的對象中,最后將RequestsCookieJar對象作為網絡請求的Cookies參數發送網絡請求即可。以獲取豆瓣網頁登錄后用戶名為例,具體步驟如下:
- 在Google瀏覽器中打開豆瓣網頁地址(https://www.douban.com/),并輸入自己的賬號+密碼登錄。
- 右鍵“檢查”,選擇“Network”選項。
- 在“name”框中選擇其中一個,在Headers選項中選擇Request Headers選項,獲取登錄后的Cookies信息(選中后右鍵“Copy value”)。
- 導入相應的模塊,將復制出來的Cookie信息粘到下面的“此處填寫登錄后網頁的Cookie信息”中,然后創建RequestsCookieJar()對象并對Cookie信息進行處理,最后將處理后的RequestsCookieJar()對象作為網絡請求參數,實現網頁的登錄請求。
讓我們試一下下面的代碼:
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'} import requests #導入requests模塊cookies = '此處填寫登錄后網頁的Cookie信息' #發送網絡請求 url = 'https://www.douban.com' #創建requestsCookieJar對象,用于設置Cookies信息 cookies_jar = requests.cookies.RequestsCookieJar() for cookie in cookies.split(';'):key,value = cookie.split('=',1)cookies_jar.set(key,value) response = requests.get(url,headers=headers,cookies=cookies_jar) print(response.status_code) #打印相應狀態碼 print(response.text) #打印相應結果1.3 Beautiful Soup解析庫
Beautiful Soup是一個可以從HTML或XML文件中提取數據的python庫。如果你不太懂HTML的相關知識,我希望您參考一下我的HTML相關博客。
1.3.1 安裝
我們需要安裝兩個東西:bs4和lxml。
pip install bs4
pip install lxml
1.3.2 對象的創建
BeautifulSoup對象代表要解析的整個文檔樹。它支持搜索文檔樹和搜索文檔樹中描述的大部分方法。
我們來試著創建一個BeautifulSoup對象。解析時,我們采用lxml解析器。
# 導入模塊 from bs4 import BeautifulSoup# 創建對象 soup = BeautifulSoup('<html>data</html>', 'lxml') print(soup)out:
<html><body><p>data</p></body></html>輸入結果時我們可以看到BeautifulSoup對象幫我們自動補全了html的標準格式。
1.3.3 find方法
BeautifulSoup擁有find方法,其作用可以用于搜索文檔樹。
find(self,name = None,attr = [],recursive = True,text = None,**kwargs)
- name:標簽名
- attrs:屬性字典
- recursive:是否遞歸循環查找,如果為False,則無法找到指定標簽的子標簽
- text:根據文本內容查找
- return :查找到的第一個元素對象
- 如果想要找到所有元素對象,可以使用findAll方法
我們來試著利用bs4來解析以下的HTML語言。
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>心得體會——塵魚</title> </head> <body><h1>浮世三千</h1><hr><h2>文章內容</h2><p>無非兩種人:一種是做了,沒成功,所以焦慮;一種是沒做,要迎接失敗了,所以焦慮。人常常會把自己的所得經驗告誡未得之人,就如同許久之前高中的恩師一般念叨;人常常會抱怨世間的不公,想要改變眼前的一切;而人在經歷了大起大落后回望,他們總是能發現:自己的付出不像童話里的那般美好,總能得到意外的對待。很少有些許的沉思,或者來自內心深處的拷問:自己至此,該干什么,身邊的人說了那么多,自己該不該反思什么。致命的慵懶總是帶來成堆的接口,漫天的抱怨似乎幽怨的黑洞,似乎解決的方法就像是時光隧道中那一絲薄弱的亮光微不可及;避開自己心里的拷問,避開一切的一切,似乎拖著拖著生活的美好就能如期而至。</p><img src="https://images.cnblogs.com/cnblogs_com/blogs/710924/galleries/2086847/o_220115052557_5af17f7f881b11ebb6edd017c2d2eca2.jpg" alt="圖片加載失敗" title="該圖片來源于塵魚好美" weight="480" height="360"><p>“日常所得焦慮,無非是三天打魚兩天曬網,時而努力時而頹廢所致?!?span id="ozvdkddzhkzd" class="token tag"></p><p>約莫些許人同此言,卻又忘卻其 “人生的悲歡并不相同,他們只覺得你吵鬧。<br>棄浮沉往事,探前方長路坎坷;棄勿須情感,奔自己心中所想。<br>繁瑣的慥詞現已無人愿細細品味,只愿將心中所得能與伯樂共享,足矣。</p>如果喜歡該案例可以關注我的網站<br><a href="https://www.cnblogs.com/ChengYuHaoMei/">點此前往</a><audio src="https://audio04.dmhmusic.com/71_53_T10051752137_128_4_4_0_sdk-cpm/cn/0103/M00/10/B5/ChR45F8hdhCAJ_unAAdXW5beNxE239.mp3?xcode=e20e7d6d765a63dc97d12357a8578f3cc746bc4" controls autoplay loop> </body> </html>讓我們動手試一下:
# 導入模塊 from bs4 import BeautifulSoup# HTML文檔對象 htmlTest = """<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>心得體會——塵魚</title> </head> <body><h1>浮世三千</h1><hr><h2>文章內容</h2><p>無非兩種人:一種是做了,沒成功,所以焦慮;一種是沒做,要迎接失敗了,所以焦慮。人常常會把自己的所得經驗告誡未得之人,就如同許久之前高中的恩師一般念叨;人常常會抱怨世間的不公,想要改變眼前的一切;而人在經歷了大起大落后回望,他們總是能發現:自己的付出不像童話里的那般美好,總能得到意外的對待。很少有些許的沉思,或者來自內心深處的拷問:自己至此,該干什么,身邊的人說了那么多,自己該不該反思什么。致命的慵懶總是帶來成堆的接口,漫天的抱怨似乎幽怨的黑洞,似乎解決的方法就像是時光隧道中那一絲薄弱的亮光微不可及;避開自己心里的拷問,避開一切的一切,似乎拖著拖著生活的美好就能如期而至。</p><img src="https://images.cnblogs.com/cnblogs_com/blogs/710924/galleries/2086847/o_220115052557_5af17f7f881b11ebb6edd017c2d2eca2.jpg" alt="圖片加載失敗" title="該圖片來源于塵魚好美" weight="480" height="360"><p>“日常所得焦慮,無非是三天打魚兩天曬網,時而努力時而頹廢所致?!?lt;/p><p>約莫些許人同此言,卻又忘卻其 “人生的悲歡并不相同,他們只覺得你吵鬧。<br>棄浮沉往事,探前方長路坎坷;棄勿須情感,奔自己心中所想。<br>繁瑣的慥詞現已無人愿細細品味,只愿將心中所得能與伯樂共享,足矣。</p>如果喜歡該案例可以關注我的網站<br><a href="https://www.cnblogs.com/ChengYuHaoMei/">點此前往</a><audio src="https://audio04.dmhmusic.com/71_53_T10051752137_128_4_4_0_sdk-cpm/cn/0103/M00/10/B5/ChR45F8hdhCAJ_unAAdXW5beNxE239.mp3?xcode=e20e7d6d765a63dc97d12357a8578f3cc746bc4" controls autoplay loop> </body> </html>"""# 創建對象 soup = BeautifulSoup(htmlTest, 'lxml')# 查找title標簽 title = soup.find("title") # 查找a標簽 a = soup.find("a") # 查找所有a標簽 a_s = soup.findAll("a")print(title) print(a) print(a_s)我們也可以不通過標簽查找內容,而通過屬性查找內容。那么我們可以使用find有參構造器中attrs屬性來構建屬性字典,從而進行查找。如下所示:
# 導入模塊 from bs4 import BeautifulSoup# HTML文檔對象 htmlTest = """<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>心得體會——塵魚</title> </head> <body><h1>浮世三千</h1><hr><h2>文章內容</h2><p>無非兩種人:一種是做了,沒成功,所以焦慮;一種是沒做,要迎接失敗了,所以焦慮。人常常會把自己的所得經驗告誡未得之人,就如同許久之前高中的恩師一般念叨;人常常會抱怨世間的不公,想要改變眼前的一切;而人在經歷了大起大落后回望,他們總是能發現:自己的付出不像童話里的那般美好,總能得到意外的對待。很少有些許的沉思,或者來自內心深處的拷問:自己至此,該干什么,身邊的人說了那么多,自己該不該反思什么。致命的慵懶總是帶來成堆的接口,漫天的抱怨似乎幽怨的黑洞,似乎解決的方法就像是時光隧道中那一絲薄弱的亮光微不可及;避開自己心里的拷問,避開一切的一切,似乎拖著拖著生活的美好就能如期而至。</p><img src="https://images.cnblogs.com/cnblogs_com/blogs/710924/galleries/2086847/o_220115052557_5af17f7f881b11ebb6edd017c2d2eca2.jpg" alt="圖片加載失敗" title="該圖片來源于塵魚好美" weight="480" height="360"><p>“日常所得焦慮,無非是三天打魚兩天曬網,時而努力時而頹廢所致?!?lt;/p><p>約莫些許人同此言,卻又忘卻其 “人生的悲歡并不相同,他們只覺得你吵鬧。<br>棄浮沉往事,探前方長路坎坷;棄勿須情感,奔自己心中所想。<br>繁瑣的慥詞現已無人愿細細品味,只愿將心中所得能與伯樂共享,足矣。</p>如果喜歡該案例可以關注我的網站<br><a href="https://www.cnblogs.com/ChengYuHaoMei/">點此前往</a><audio src="https://audio04.dmhmusic.com/71_53_T10051752137_128_4_4_0_sdk-cpm/cn/0103/M00/10/B5/ChR45F8hdhCAJ_unAAdXW5beNxE239.mp3?xcode=e20e7d6d765a63dc97d12357a8578f3cc746bc4" controls autoplay loop> </body> </html>"""# 創建對象 soup = BeautifulSoup(htmlTest, 'lxml')# 根據title屬性查找img內容 img = soup.find(attrs={'weight': "480"}) print(img)1.3.4 后話
實際上,解析庫不止有bs4,還有Xpath、selenium和Scrapy框架。這些后面我想單獨再講,這里有bs4已經足夠爬取大部分的網頁內容了。
1.4 正則表達式
1.4.1 正則表達式語法
正則表達式可以用于字符串匹配。其可以檢查一個字符串是否含有某種子串,還可以替換匹配的子串,最后還能提取某個字符串匯總匹配的子串。
讓我們來看一下正則表達式的語法。
| . | 匹配除換行符以外的任意字符 |
| \ | 轉義字符,能使的改變字符原本的意思,變為字符串 |
| […] | 字符集。對應的位置可以是字符集中任意字符。如a[a-c]d,那么其匹配結果是aad、abd、acd。如果要取反,加上^即可。如a[ ^a-c ],其可以匹配除了aa、ab、ac以外的任何帶a開頭的兩位英文字符串。 |
動手試一下吧,能夠加深你的印象。
# 正則表達式的常見語法 import re# 字符匹配 str1 = 'abcdefg' rs = re.findall('abc', str1) rs1 = re.findall('a.c', str1) print(f"字符串匹配結果{rs}") print(f"點的匹配結果{rs1}") str2 = 'a.bcdfg' rs2 = re.findall('a\..c', str2) print(f"用轉義字符匹配點{rs2}") rs3 = re.findall('a[bc]c', str1) print(f"用字符集匹配{rs3}")對于字符集來說,里面可以填上一些字符。
| \d | 匹配數字0-9 |
| \D | 匹配^\d |
| \s | 匹配空白字符 |
| \S | 匹配非空白字符 |
| \w | 匹配普通字符,相當于[A-Za-z0-9_] |
| \W | 匹配非英語字母 |
除了以上的字符之外,還有一些數量詞。它們一般用于字符或字符集之后。
| * | 匹配前一個字符0或無限次 | abc* | ab,abccc |
| + | 匹配前一個字符1次或無限次 | abc+ | abc,abccc |
| ? | 匹配前一個字符0次或1次 | acb? | ab,abc |
| {m} | 匹配前一個字符m次 | ab{2}c | abbc |
1.4.2 re.findall()方法
re.findall(pattern,string,flag = 0)
- 掃描整個string字符串,返回所有與pattern匹配的列表
- pattern:正則表達式
- string:從那個字符串中尋找
- flags:匹配模式
在上面的操作中,我們使用小括號進行分組,其中分組是用于返回括號內匹配的結果,如果不加分組則返回整個字符串;當加了分組后,小括號兩旁的字符串是用于定位的。
1.4.3 r原串的使用
在我們不使用r原串時,如果我們想要匹配轉義符怎么匹配?我們需要四個斜桿。即如果想用正則表達式匹配\,則需要\\\\。
對于re模塊來說,其為我們提供了r原串來解決上述的問題。我們來看一下下面的例子:
import re# 1 不使用r原串,遇到轉義符怎么辦 rs = re.findall('a\\\nbc', 'a\nbc') print(rs)# 2 使用r原串 rs = re.findall(r'a\nbc', 'a\nbc') print(rs)1.4.4 案例
讓我們來試著利用所學知識提取一下疫情的json字符串,注意,這里可能還有人不認識json是什么,下一講我們會做闡述,這里我們應該關注的是,如何爬蟲和如何正則匹配。
鏈接:全球新冠肺炎疫情地圖 - 丁香園·丁香醫生 (dxy.cn)
import requests from bs4 import BeautifulSoup import re# 1 獲取首頁內容 # 發送請求,獲取響應 response = requests.get('http://ncov.dxy.cn/ncovh5/view/pneumonia') # 從響應中獲取數據 page = response.content.decode()# 2 提取各國疫情數據 # 構建bs對象 soup = BeautifulSoup(page, 'lxml') # 查找標簽 script = soup.find(id='getListByCountryTypeService2true') # 獲取標簽內容 countries_text = script.text # 提取json字符串 json_str = re.findall(r"(\[.*\])", countries_text) print(json_str)1.5 json
1.5.1 json模塊
JSON全名JavaScript Object Notation(JavaScript 對象表示法),它是存儲和交換文本信息的語法,類似 XML。JSON 比 XML 更小、更快,更易解析。其和python數據類型區別如下:
我們來看一段json的文件:
{"sites": [{ "name":"google" , "url":"www.google.com" }, { "name":"微博" , "url":"www.weibo.com" }] }python中提供了json模塊,其可用于json格式的文件數據和python文件數據的相互轉換。
如何實現裝換呢?如果我們是要是json字符串轉化為python類型數據的話,只需調用json.load(),將字符串傳給構造器即可。
同樣地,如果你想將json文件轉為python類型的數據,那么首先要實例化json文件,讓其變為對象,然后再將對象傳入json.load()的構造器中。
import json# 1 把json字符串轉換為python數據 json_str = """{"sites": [{ "name":"google" , "url":"www.google.com" }, { "name":"微博" , "url":"www.weibo.com" }] }"""rs = json.loads(json_str) # print(rs)# 2 把json格式文件轉換為python類型的數據 with open('Test.json') as fp:python_list = json.load(fp)print(python_list)1.5.2 python轉json
轉換原理如下所示:
import json# 1 python數據轉換為json數據 # json轉python json_str = """{"sites": [{ "name":"google" , "url":"www.google.com" }, { "name":"微博" , "url":"www.weibo.com" }] }""" rs = json.loads(json_str) # print(rs)# python轉json json_str = json.dumps(rs, ensure_ascii=False) # print(json_str)# 2 把python以json格式存儲到文件中 with open('test.json', 'w') as fp:json.dump(rs, fp, ensure_ascii=False)1.5.3 案例
讓我們繼續1.4.4中json字符串轉換為python的過程。
import json import requests from bs4 import BeautifulSoup import re# 1 獲取首頁內容 # 發送請求,獲取響應 response = requests.get('http://ncov.dxy.cn/ncovh5/view/pneumonia') # 從響應中獲取數據 page = response.content.decode()# 2 提取各國疫情數據 # 構建bs對象 soup = BeautifulSoup(page, 'lxml') # 查找標簽 script = soup.find(id='getListByCountryTypeService2true') # 獲取標簽內容 countries_text = script.text # 提取json字符串 json_str = re.findall(r"\[.*\]", countries_text)[0] print(json_str)# 3 把json字符串轉換為python類型數據 last_day_corona_virus = json.loads(json_str) print(last_day_corona_virus)總結
以上是生活随笔為你收集整理的网络爬虫(一)——爬虫及其实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: asp.net 强制性单一登陆现实
- 下一篇: 学习笔记-java编程-交通灯管理器设计