python爬虫基础(一)~爬虫概念和架构
目錄
1. 爬蟲
1.1 概念
1.2 分類
2. 爬蟲架構
2.1 url管理器
2.2 網頁(html)下載(download)器
2.2.1 urllib下載html源碼
2.2.2 requests下載html源碼
2.3 網頁(html)解析(parser)器
2.3.1 BeautifulSoup解析包
2.3.2 xpath解析包
2.4 數據存儲器
2.4.1 保存文本
2.4.2 保存圖片
2.4.3 保存表格table數據
2.4.4?將數據重復寫入已存在的excel文件
3. 爬蟲難點要點
3.1 設置headers
3.2 字符編解碼知識
3.3?爬取動態頁面?
3.4?爬蟲爬取的圖片損壞、無法打開
3.5 異常處理
3.6 如何獲取兩個不同之間的所有文本
參考
1. 爬蟲
1.1 概念
參考:百度百科~爬蟲
網絡爬蟲(又稱為網頁蜘蛛,網絡機器人,在FOAF社區中間,更經常的稱為網頁追逐者),是一種按照一定的規則,自動地抓取html網頁信息的程序或者腳本。另外一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲。
1.2 分類
- 通用網絡爬蟲。又稱全網爬蟲(Scalable Web Crawler),爬行對象從一些種子 URL 擴充到整個 Web,主要為門戶站點搜索引擎和大型 Web 服務提供商采集數據。?商業應用,很少個人使用。
- 聚焦網絡爬蟲(Focused Crawler)。又稱主題網絡爬蟲(Topical Crawler),是指選擇性地爬行那些與預先定義好的主題相關頁面的網絡爬蟲。我們通常意義上說的爬蟲,給定詞或者url,爬取想要的網頁內容。--我認為是個人初級爬蟲
- 增量式網絡爬蟲(Incremental Web Crawler)。是指對已下載網頁采取增量式更新和只爬行新產生的或者已經發生變化網頁的爬蟲,它能夠在一定程度上保證所爬行的頁面是盡可能新的頁面。針對特定網頁,及時發現、爬取更新信息,?并可以發送郵件通知用戶。---我認為是個人中級爬蟲
- Deep Web 爬蟲Web 頁面按存在方式可以分為表層網頁(Surface Web)和深層網頁(Deep Web,也稱 Invisible Web Pages 或 Hidden Web)。 表層網頁是指傳統搜索引擎可以索引的頁面,以超鏈接可以到達的靜態網頁為主構成的 Web 頁面。Deep Web 是那些大部分內容不能通過靜態鏈接獲取的、隱藏在搜索表單后的,只有用戶提交一些關鍵詞才能獲得的 Web 頁面。例如那些用戶注冊后內容才可見的網頁就屬于 Deep Web。 2000 年 Bright Planet 指出:Deep Web 中可訪問信息容量是 Surface Web 的幾百倍,是互聯網上最大、發展最快的新型信息資源。
2. 爬蟲架構
用python3!python3!python3!python2已經過時了
2.1 url管理器
管理將要爬取的url和已經爬取的url,將待爬取的url傳送給網頁下載器。
2.2 網頁(html)下載(download)器
將url指定的網頁下載下來,保存為一個json字符串,然后將這個字符串傳送給html解析器解析。
download packages:requests,?urllib
html download包含三個核心部分:
- 構造url請求對象
- 發送url請求,獲取響應
- 讀取/下載html全部網頁內容
2.2.1 urllib下載html源碼
# 訪問、下載html網頁url = 'https://baike.baidu.com/item/' + urllib.parse.quote(content) # 請求地址# 請求頭部,偽造瀏覽器,防止爬蟲被反headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}# 利用請求地址和請求頭部構造請求對象req = urllib.request.Request(url=url, headers=headers, method='GET')response = urllib.request.urlopen(req) # 發送請求,獲得響應text = response.read().decode('utf-8') # 讀取響應,獲得文本urllib.parse.quote(content) <--因為url只允許一部分ascii字符,其他字符(如漢子)是不符合標準的,此時就要進行編碼。
urllib.request.Request --> urlopen()方法可以實現最基本構造HTTP請求的方法,但如果加入headers等信息,就可以利用Request類來構造請求。
2.2.2 requests下載html源碼
#coding=utf-8 import requests from bs4 import BeautifulSoupresp=requests.get('https://www.baidu.com') #請求百度首頁 print(resp) #打印請求結果的狀態碼 print(resp.content) #打印請求到的網頁源碼bsobj=BeautifulSoup(resp.content,'lxml') #將網頁源碼構造成BeautifulSoup對象,方便操作 a_list=bsobj.find_all('a') #獲取網頁中的所有a標簽對象 text='' # 創建一個空字符串 for a in a_list:href=a.get('href') #獲取a標簽對象的href屬性,即這個對象指向的鏈接地址text+=href+'\n' #加入到字符串中,并換行 with open('url.txt','w') as f: #在當前路徑下,以寫的方式打開一個名為'url.txt',如果不存在則創建f.write(text) #將text里的數據寫入到文本中-->注意:百度爬取的html有靜態頁面和動態頁面。靜態簡單,比如百度百科;動態困難,比如淘女郎,參考:https://blog.csdn.net/aaronjny/article/details/80291997
2.3 網頁(html)解析(parser)器
一方面,html parser會解析出有價值的數據;另一方面,解析出字符串中的url,將其補充到url管理器。這三個模塊形成了一個循環,只要有未爬取的url,這個循環就會一直繼續下去。
parser packages:?bs4, lxml, xpath。正則表達式用于提取解析器提取不到的數據!!!
html parser包含三個核心內容:
- 解析html內容
- 抽取特定標簽,返回一個標簽列表
- 獲取標簽文本/屬性值
2.3.1 BeautifulSoup解析包
將網頁源碼解析成BeautifulSoup對象,方便操作
抽取標簽方法:find()方法、find_all()方法、select()方法
獲取標簽文本、屬性值方法:text()方法、get_text()方法、get()方法
具體方法介紹,看我的第二篇博客:python爬蟲基礎(二)~工具包: 下載包requests、urllib和解析包BeautifulSoup(bs4)、xpath,https://blog.csdn.net/qq_33419476/article/details/117394430
# 爬取圖片# 找到所有img標簽,返回一個url的標簽列表img_urllist = []resp = requests.get(url=url, headers=headers)content = resp.contentsoup = BeautifulSoup(content, 'lxml')# img_list = soup.select('div .album-wrap')img_list = soup.select('a>div>img')print(img_list)for img in img_list:try:# src = img.find('img').get('src')src = img.get('src')if re.match(r'https:(.*)image(.*)auto$', src):img_urllist.append(src)except:continue2.3.2 xpath解析包
def query(content):# 請求地址url = 'https://baike.baidu.com/item/' + urllib.parse.quote(content)# 請求頭部headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}# 利用請求地址和請求頭部構造請求對象req = urllib.request.Request(url=url, headers=headers, method='GET')# 發送請求,獲得響應response = urllib.request.urlopen(req)# 讀取響應,獲得文本text = response.read().decode('utf-8')# 構造 _Element 對象html = etree.HTML(text)# 使用 xpath 匹配數據,得到匹配字符串列表sen_list = html.xpath('//div[contains(@class,"lemma-summary")]//text()')print(sen_list)# 過濾數據,去掉空白sen_list_after_filter = [item.strip('\n') for item in sen_list if item != '\n']# 將字符串列表連成字符串并返回return ''.join(sen_list_after_filter)2.4 數據存儲器
2.4.1 保存文本
- 寫入--"w"; 追加--"a"
source:菜鳥教程,https://www.runoob.com/python/python-func-open.html
| t | 文本模式 (默認)。 |
| x | 寫模式,新建一個文件,如果該文件已存在則會報錯。 |
| b | 二進制模式。 |
| + | 打開一個文件進行更新(可讀可寫)。 |
| U | 通用換行模式(不推薦)。 |
| r | 以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。 |
| rb | 以二進制格式打開一個文件用于只讀。文件指針將會放在文件的開頭。這是默認模式。一般用于非文本文件如圖片等。 |
| r+ | 打開一個文件用于讀寫。文件指針將會放在文件的開頭。 |
| rb+ | 以二進制格式打開一個文件用于讀寫。文件指針將會放在文件的開頭。一般用于非文本文件如圖片等。 |
| w | 打開一個文件只用于寫入。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。 |
| wb | 以二進制格式打開一個文件只用于寫入。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。一般用于非文本文件如圖片等。 |
| w+ | 打開一個文件用于讀寫。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。 |
| wb+ | 以二進制格式打開一個文件用于讀寫。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。一般用于非文本文件如圖片等。 |
| a | 打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創建新文件進行寫入。 |
| ab | 以二進制格式打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創建新文件進行寫入。 |
| a+ | 打開一個文件用于讀寫。如果該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。如果該文件不存在,創建新文件用于讀寫。 |
| ab+ | 以二進制格式打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結尾。如果該文件不存在,創建新文件用于讀寫。 |
2.4.2 保存圖片
需要用二進制, 'wb'
with open(file_path, 'wb') as f:f.write(soup.content)2.4.3 保存表格table數據
- 工信部表格數據保存方法,source:https://blog.csdn.net/zhang862520682/article/details/86701078
- 百度百科表格數據保存
2.4.4?將數據重復寫入已存在的excel文件
# 保存信息框數據到excelif not os.path.exists('profile'):os.mkdir('profile')profile_file = project_path + '/profile/' + 'profile.csv'field_list = ['中文名', '外文名', '別名', '性別', '學位', '職稱', '國籍', '民族', '出生地', '籍貫', '出生日期', '逝世日期','星座', '血型', '身高','體重', '畢業院校', '職業', '經紀公司', '代表作品', '主要成就', '生肖', '語種', '特長', '粉絲名']if not os.path.exists(profile_file):workbook = xlwt.Workbook(encoding='utf-8')output_sheet = workbook.add_sheet('profile_sheet', cell_overwrite_ok=True)for i in range(len(field_list)):output_sheet.write(0, i, field_list[i])workbook.save(profile_file)rb = xlrd.open_workbook(profile_file)rows_num = rb.sheet_by_name('profile_sheet').nrows# print(rows_num)wb = copy(rb)output_sheet = wb.get_sheet(0)# print(profile)for i in range(len(field_list)):if profile_dict.get(field_list[i]):output_sheet.write(rows_num, i, profile_dict.get(field_list[i]))else:continueos.remove(profile_file)wb.save(profile_file)3. 爬蟲難點要點
3.1 設置headers
- 偽造火狐瀏覽器的headers
- 自己設置headers ??
session是requests庫中的一個類,創建session對象進行訪問的好處是,session對象能夠自動維護訪問的cookies信息(通過js修改的cookies信息它是記錄不到的)
--> 為啥要記錄cookies信息:因為有些站點的服務器會驗證你的cookies信息,當cookies信息不正確時,服務器會拒絕你的訪問。
--> 設置headers和data的目的:是為了將本次請求偽裝成瀏覽器的請求,并通過傳遞的數據控制服務器返回我們需要的信息。
————————————————
版權聲明:本文為CSDN博主「筆墨留年」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/aaronjny/article/details/80291997
3.2 字符編解碼知識
現在html網頁基本都采用utf-8編碼,在爬蟲爬取網頁時不必過多關注網頁的編解碼。
以前,request返回的消息編碼為gb2312,我們需要先進行解碼decode('utf-8'),才不會出現亂碼。比如:淘女郎case,因為主頁源碼為gbk編碼,所以需要先用gbk對其解碼。
唯一一個例外時urllib發送url請求獲取網頁源碼時,需要先解碼decode('utf-8'),再進行網頁解析,不然會出現亂碼。
延伸閱讀:https://www.crifan.com/summary_explain_what_is_html_charset_and_common_value_of_gb2312_gbk_utf_8_iso8859_1/
3.3?爬取動態頁面?
source:?淘女郎case
problem: 爬取的內容是從源碼取得的,但是在頁面中看到了內容,在源碼里面卻沒有,why?
analysis: 這就是動態頁面抓取。當我們訪問這個網址的時候,瀏覽器返回給我們的只有一部分信息。 ==> "數據加載中" 實際上,服務器先給我們返回了這個頁面,然后又通過ajax技術,請求了另外一個借口。接口返回了淘女郎們的信息,隨后瀏覽器運行javascript代碼,將這些信息填充到先前額頁面中。因此,我們才在頁面中看到了淘女郎們的信息。
(源碼頁面 -> 檢查 -> 網絡 -> 內容信息)
3.4?爬蟲爬取的圖片損壞、無法打開
--> attention:需要用二進制binary格式保存圖片,即'wb'
problem:pycharm?imge not loaded try to open it enternally to fix format problem
analysis:原因是不能用bref圖片網址保存圖片,需要用src圖片網址保存圖片
by the way:我送你解析圖片標簽過程中,過濾無效img圖片的正則表達式
# img_list = soup.select('div .album-wrap')img_list = soup.select('a>div>img')# print(img_list)for img in img_list:try:# src = img.find('img').get('src')src = img.get('src')if re.match(r'https:(.*)image(.*)auto$', src):img_urllist.append(src)except:continue至于為啥用soup.select()而不是soup.find_all()? 我個人認為,select()方法兼容方法更多,更關鍵的是,它支持提取子標簽匹配規則,即:'a>div>img'。
by the way: 提取標簽中子標簽的屬性值
src = img.find('img').get('src')3.5 異常處理
- SSL: CERTIFICATE_VERIFY_FAILED。因為當使用urllib.urlopen打開一個 https 鏈接時,會驗證一次 SSL 證書。
- 怎么去除抓取數據中的'\xa0\xa0\xa0\xa亂碼 -->?''.join(str.split())方法,但是這種方法會刪除原有文本中的空格
- 如何刪除爬取的html網頁內容中的NBSP-亂碼空格,string.replace(u'\xa0', u' ')
3.6 如何獲取兩個不同之間的所有文本
BeautifulSoup_object的previous_sibling、previous_siblings 和?next_sibling、next_siblings方法,可以獲取同級標簽文本,即兄弟節點的文本。?
source:https://blog.csdn.net/u011378313/article/details/79086508;https://blog.csdn.net/weixin_38517397/article/details/108207928?
sibling_soup = BeautifulSoup(sibling_html, 'html.parser') br = sibling_soup.p while br.next_sibling != None:print brbr = br.next_sibling --------------------------------------------------------------- for tag in soup.select('div .col-md-4'):if tag.get_text() == 'Total':result = tag.next_sibling.get_text()--> 判斷each br?in 返回的標簽兄弟節點列表 是否是標簽,因為有些兄弟節點為空。
for br in i.next_siblings: # 獲取人物履歷標簽后面所有的兄弟標簽# print(br)if type(br) is bs4.element.Tag: # 判斷br是不是一個標簽attrs = ''.join(br.attrs['class'])if attrs == 'para':br_text_list.append(br.get_text())elif attrs == re.compile('para-title level'):breakelse:continuesource:http://www.voidcn.com/article/p-eqwgopwx-bvx.html
from bs4 import BeautifulSoupsoup = BeautifulSoup("""<html><div class="lead">lead</div>data<div class="end"></div></html>"""", "lxml")node = soup.find('div', {'class': 'lead'}) s = [] while True:if node is None:breaknode = node.next_siblingif hasattr(node, "attrs") and ("end" in node.attrs['class'] ):break else:if node is not None:s.append(node) print s參考
[1]?爬蟲實戰(一) 用Python爬取百度百科,?https://www.cnblogs.com/wsmrzx/p/10531708.html
[2]?python爬蟲入門教程(二):開始一個簡單的爬蟲,?https://blog.csdn.net/aaronjny/article/details/77945329
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的python爬虫基础(一)~爬虫概念和架构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习数学基础(一)~卷积
- 下一篇: websocket python爬虫_p