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