- 本博客是《Python爬蟲入門》系列的第一篇博客,主要介紹爬蟲涉及到的一些基礎知識,如HTTP協議、網頁基礎知識、Requests庫的基本用法等
- 學習交流請聯繫 [email protected]
文章目錄
基本概念
互聯網
- 互聯網也叫因特網(Internet),是指網絡與網絡所串聯成的龐大網絡,這些網絡以一組標準的網絡協議族相連,連接全世界幾十億個設備,形成邏輯上的單一巨大國際網絡。
- 它由從地方到全球範圍內幾百萬個私人的、學術界的、企業的和政府的網絡所構成。通過電子、無線和光纖等一系列廣泛的技術來實現。
- 這種將計算機網絡互相連接在一起的方法可稱作“網絡互聯”,在此基礎上發展出來的覆蓋全世界的全球性互聯網絡稱爲“互聯網”,即相互連接在一起的網絡。
提示:
互聯網並不等於萬維網(WWW),萬維網只是一個超文本相互鏈接而成的全球性系統,而且是互聯網所能提供的服務之一。互聯網包含廣泛的信息資源和服務,例如相互關聯的超文本文件,還有萬維網的應用,支持電子郵件的基礎設施、點對點網絡、文件共享,以及IP電話服務。
HTTP協議
簡介
- HTTP(Hypertext Transfer Protocol)協議,即超文本傳輸協議,是一個基於“請求與響應”模式的、無狀態的應用層協議
- HTTP協議採用URL作爲定位網絡資源的標識,URL格式爲http://host[:port][path]
- host:合法的Internet主機域名或IP地址
- port:端口號,缺省端口爲80
- path:請求資源的路徑
- URL是通過HTTP協議存取資源的Internet路徑,一個URL對應一個數據資源
操作
方法 | 說明 |
---|---|
GET | 請求獲取URL位置的資源 |
HEAD | 請求獲取URL位置資源的響應消息報告,即獲得該資源的頭部信息 |
POST | 請求向URL位置的資源後附加新的數據 |
PUT | 請求向URL位置存儲一個資源,覆蓋原URL位置的資源 |
PATCH | 請求局部更新URL位置的資源,即改變該處資源的部分內容 |
DELETE | 請求刪除URL位置存儲的資源 |
TRACE | 回顯服務器收到的請求,主要用於測試或診斷 |
OPTIONS | 使服務器傳回該資源所支持的所有HTTP請求方法 |
網頁基礎
因爲我們抓取的數據常來源於網頁,因此有必要了解一下網頁的基礎知識。
網頁組成
網頁通常由由 HTML 、 CSS 、JavaScript 三部分組成:
- HTML 即超文本標記語言(Hypertext Markup Language),用來創建網頁
- CSS 即層疊樣式表(Cascading Style Sheets),用於美化網頁
- JavaScript 用於用戶和網頁之間的交互
我們打開 Chrome 瀏覽器,訪問博客站的首頁,打開 F12 開發者工具,可以看到:
在選項 Elements 中可以看到網頁的源代碼,這裏展示的就是 HTML 代碼
- 不同類型的文字通過不同類型的標籤來表示,如圖片用
<img>
標籤表示,視頻用<video>
標籤表示,段落用<p>
標籤表示,它們之間的佈局又常通過佈局標籤<div>
嵌套組合而成,各種標籤通過不同的排列和嵌套才形成了網頁的框架 - 在右邊 Style 標籤頁中,顯示的就是當前選中的 HTML 代碼標籤的 CSS 層疊樣式。層疊是指當在HTML中引用了數個樣式文件,並且樣式發生衝突時,瀏覽器能依據層疊順序處理。“樣式”指網頁中文字大小、顏色、元素間距、排列等格式
- JavaScript 在 HTML 代碼中常用
<script>
進行包裹,可直接寫在 HTML 頁面,也可以文件的形式引入
網頁結構
我們來手寫一個簡單 HTML 頁面來感受下:
創建一個文本文件,將後綴名改爲 .html ,比如demo.html,寫入如下內容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<body>
<div id="container">
<div class="wrapper">
<h1>Hello World</h1>
<div>Hello Python.</div>
</div>
</div>
</body>
</html>
觀察代碼,我們發現:
- 整個文檔是以 DOCTYPE 來開頭的,這裏定義了文檔類型是 html ,整個文檔最外層的標籤是 ,並且結尾還以 來表示閉和
- 整個 HTML 文檔一般分爲 head 和 body 兩個部分
- 在 head 中,我們一般會指定當前的編碼格式爲 UTF-8 ,並且使用 title 來定義網頁的標題,這個會顯示在瀏覽器的標籤上面
- body 中的內容一般爲整個 html 文檔的正文,html的標籤由
<h1>
到<h6>
六個標籤構成,字體由大到小遞減,換行標籤爲<br>
,鏈接使用<a>
來創建,herf屬性包含鏈接的URL地址,比如<a href="http://www.baidu.com" >一個指向百度的鏈接</a>
HTML DOM
在 HTML 中,所有標籤定義的內容都是節點,它們構成了一個 HTML DOM 樹
根據 W3C 的 HTML DOM 標準,HTML 文檔中的所有內容都是節點:
- 整個文檔是一個文檔節點
- 每個 HTML 元素是元素節點
- HTML 元素內的文本是文本節點
- 每個 HTML 屬性是屬性節點
- 註釋是註釋節點
HTML DOM 將 HTML 文檔視作樹結構。這種結構被稱爲節點樹:
節點樹中的節點彼此擁有層級關係
父(parent)、子(child)和同胞(sibling)等術語用於描述這些關係。父節點擁有子節點。同級的子節點被稱爲同胞(兄弟或姐妹):
- 在節點樹中,頂端節點被稱爲根(root)
- 每個節點都有父節點、除了根(它沒有父節點)
- 一個節點可擁有任意數量的子
- 同胞是擁有相同父節點的節點
下面的圖片展示了節點樹的一部分,以及節點之間的關係:
使用開發者工具檢查網頁
如果想要編寫一個爬取網頁內容的爬蟲程序,在動手編寫前,最重要的準備工作可能就是檢查目標網頁。下面以Chrome爲例,看看如何使用開發者工具。
以python官網的“python之禪”爲例,首先在Chrome中打開網址 ,可以選擇“菜單”中的“更多工具”→“開發者工具”,也可以直接在網頁內容中右擊並選擇“檢查”選項,還可以按f12鍵。效果如下圖所示:
Chrome的開發者模式爲用戶提供了下面幾組工具:
- Elements:允許用戶從瀏覽器的角度來觀察網頁,用戶可以藉此看到Chrome渲染頁面所需要的HTML、CSS和DOM(Document Object Model)對象
- Network:可以看到網頁向服務氣請求了哪些資源、資源的大小以及加載資源的相關信息。此外,還可以查看HTTP的請求頭、返回內容等
- Source:即源代碼面板,主要用來調試JavaScript
- Console:即控制檯面板,可以顯示各種警告與錯誤信息。在開發期間,可以使用控制檯面板記錄診斷信息,或者使用它作爲shell在頁面上與JavaScript交互
- Performance:使用這個模塊可以記錄和查看網站生命週期內發生的各種事情來提高頁面運行時的性能
- Memory:這個面板可以提供比Performance更多的信息,比如跟蹤內存泄漏。
- Application:檢查加載的所有資源
- Security:即安全面板,可以用來處理證書問題等
Requests庫
簡介
- Requests庫是Python中最爲常用的第三方爬蟲庫,用它可以解決中小規模的爬取需求。簡單易用,備受歡迎。
- 詳情可見官方網站
方法
Requests庫的方法和HTTP協議的操作大多數都是對應的,因此十分易於理解
方法 | 說明 |
---|---|
request.request() | 構造一個請求,支撐以下各方法的基礎方法 |
request.get() | 獲取HTML網頁的主要方法,對應於HTTP的GET |
request.head() | 獲取HTML網頁頭信息的主要方法,對應於HTTP的HEAD |
request.post() | 向HTML網頁提交POST請求的方法,對應於HTTP的POST |
request.put() | 獲取HTML網頁的主要方法,對應於HTTP的PUT |
request.patch() | 獲取HTML網頁的主要方法,對應於HTTP的PATCH |
request.delete() | 獲取HTML網頁的主要方法,對應於HTTP的DELETE |
解析
requests.request()
r = requests.request(method,url,**kwargs)
- method:請求方式,對應get/head/post/put/patch/delete/options七種方法
- url:擬爬取頁面的鏈接
- **kwargs:13個控制訪問的參數
- params:字典或字節流,作爲參數增加到url中
kv = {“key1”:“value1”,“key2”:“value2”}
r = requests.request(“GET”,‘http://python123.io/ws’,params=kv)
print(r.url)
- data:字典、字節序列或文件對象,作爲Request的內容
kv = {“key1”:“value1”,“key2”:“value2”}
r = requests.request(‘POST’,‘http://python123.io/ws’,data=kv)
- json:JSON格式的數據,作爲Request的內容
kv = {“key1”:“value1”,“key2”:“value2”}
r = requests.request(‘POST’,“http://python123.io/ws”,json=kv)
- headers:字典,HTTP定製頭
hd = {‘user-agent’:‘Chrome/10’}
r = requests.request(‘POST’,‘http://python123.io/ws’,headers=hd)
-
cookies:字典或CookieJar,Request中的cookie
-
auth:元組,支持HTTP認證功能
-
files:字典類型,傳輸文件
-
timeout:設定超時時間,秒爲單位
-
proxies:字典類型,設定訪問代理服務器,可以增加登錄認證
-
allow_redirects:True/False,默認爲True,重定向開關
-
stream:True/False,默認爲True,獲取內容立即下載開關
-
verify:True/False,默認爲True,認證SSL證書開關
-
cert:本地SSL證書路徑
requests.get()
r = requests.get(url,params=None,**kwargs)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nYXS5crO-1587469611585)(…/images/response.jpg)]
- r:返回一個包含服務器資源的Response對象
- requests.get():構造一個向服務器請求資源的Request對象
- url:擬爬取頁面的url連接
- params:url的額外參數,字典或字節流格式,可選
- **kwargs:12個控制訪問的參數
Response對象的屬性
屬性 | 說明 |
---|---|
r.status_code | HTTP請求的返回狀態,200表示連接成功,404表示失敗 |
r.text | HTTP響應內容的字符串形式,即url對應的頁面內容 |
r.encoding | 從HTTP header中猜測的響應內容編碼方式 |
r.apparent_encoding | 從內容中分析出的響應內容編碼方式(備選) |
r.content | HTTP響應內容的二進制形式 |
Response庫的異常
異常 | 說明 |
---|---|
requests.ConnectionError | 網絡連接錯誤異常,如DNS查詢失敗,拒絕連接等 |
requests.HTTPError | HTTP錯誤異常 |
requests.URLRequired | URL缺失異常 |
requests.TooManyRedirects | 超過最大重定向次數,產生重定向異常 |
requests.ConnectTimeout | 連接遠程服務器超時異常 |
requests.Timeout | 請求URL超時異常 |
r.raise_for_status() | 如果不是200,產生HTTP錯誤異常 |
requests.head()
requests.head(url,**kwargs)
- url:擬爬取頁面的url鏈接
- **kwargs:12個控制訪問的參數
requests.post()
requests.post(url,data=None,json=None,**kwargs)
- url:擬更新頁面的url鏈接
- data:字典、字節序列或文件,Request的內容
- json:JSON格式的數據,Request的內容
- **kwargs:12個控制訪問的參數
requests.put()
requests.put(url,data=None,**kwargs)
- url:擬更新頁面的url鏈接
- data:字典、字節序列或文件,Request的內容
- **kwargs:12個控制訪問的參數
requests.patch()
requests.patch(url,data=None,**kwargs)
- url:擬更新頁面的url鏈接
- data:字典、字節序列或文件,Request的內容
- **kwargs:12個控制訪問的參數
requests.delete()
requests.delete(url,**kwargs)
- url:擬刪除頁面的url鏈接
- **kwargs:12個控制訪問的參數
框架
import requests
def getHTMLText(url):
try:
r = requests.get(url,timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return "產生異常"
if __name__ == "__main__":
url = "<網址>"
print(getHTMLText(url))
示例
京東商品頁面爬取
import requests
url = "https://item.jd.com/100003434260.html" # 爬取網址
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000]) # 輸出字符串的前1000項
except:
print("爬取失敗")
網絡圖片爬取
- 網絡圖片的鏈接格式爲http://www.example.com/picture.jpg
- 由於每個網站對鏈接的格式設定不同,因此圖片鏈接格式往往顯得甚是複雜,但是許多參數都可以簡化省略
- 最簡單暴力的方法是鼠標右鍵複製圖片地址,然後get即可
# 針對規範路徑存儲的圖片
import requests
import os
url = "http://b-ssl.duitang.com/uploads/item/201512/15/20151215215946_dEQ5F.jpeg"
root = "C:/Users/SHOHOKU/Desktop/Python/Codes/images/" #定義系統存儲路徑
path = root + url.split('/')[-1] # url鏈接以/劃分的最後一位,即圖片的名稱
try:
if not os.path.exists(root): #判斷根目錄是否存在
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,"wb") as f:
f.write(r.content)
f.close()
print("文件保存成功")
else:
print("文件已存在")
except:
print("爬取失敗")
豆瓣TOP250榜單爬取
import requests
import os
if not os.path.exists('image'):
os.mkdir('image')
def parse_html(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"} # 僞裝頭部信息
res = requests.get(url, headers=headers)
text = res.text
item = []
for i in range(25):
text = text[text.find('alt')+3:]
item.append(extract(text))
return item
def extract(text):
text = text.split('"')
name = text[1]
image = text[3]
return name, image
def write_movies_file(item, stars):
print(item)
with open('C:/userdouban_film.txt','a',encoding='utf-8') as f:
f.write('排名:%d\t電影名:%s\n' % (stars, item[0]))
r = requests.get(item[1])
with open('image/' + str(item[0]) + '.jpg', 'wb') as f:
f.write(r.content)
def main():
stars = 1
for offset in range(0, 250, 25):
url = 'https://movie.douban.com/top250?start=' + str(offset) +'&filter='
for item in parse_html(url):
write_movies_file(item, stars)
stars += 1
if __name__ == '__main__':
main()