最近閒着,想學一下爬蟲 (^-^)V ——[手動比耶]
先從簡單的練習開始吧~ 爬取單個網頁裏的所有圖片,這個沒有什麼難點,因爲不需要翻頁哈哈哈哈。
我很喜歡一些文章中的配圖,比如這篇,裏面就會有很多電影中的經典截圖。
第一步:分析網頁
首先需要了解要爬取網站的頁面,查看網頁源代碼。然後根據網頁源代碼的結構,想好代碼的步驟和思路。
在網頁中查看頁面的源代碼(F12)
-
先來看一下頁面的請求方式:
在開發者模式的Network裏找到.html的請求,可以看到請求方式是GET請求,也沒有帶什麼特殊的請求參數之類的~ 比較簡單。
(如果沒有看到.html的請求,刷新一下頁面就出來了)
-
然後再看代碼結構:
(不太熟悉html的小夥伴可以使用圈圈裏的小箭頭,點一下自己想要看的元素,然後右側就會自動跳轉到該元素對應的代碼區域的~四不四很簡單)結合“上下文”簡單分析一下就會發現:(有種做閱讀理解的感覺hhhhh)
① 這個網頁裏所有的圖片都是放在<img>
標籤裏的src
後面,src
後面這個鏈接就是圖片的地址
(可以複製下來在瀏覽器打開確認一下)
② 圖片上方的描述語是放在class="pictext"
的p
標籤裏的
(曾打算過用這個描述語句作爲爬下來的圖片的名稱的)
這樣一來就很簡單了
只需要先拿到網頁的 HTML 代碼,然後把頁面裏面所有<img>
標籤裏的src
後面超鏈接的內容取出來就行了!
第二步:開始編程
1. 定義庫
- 首先需要用 requests 庫來發出一個網絡請求:
import requests
- 然後需要用 BeautifulSoup 來解析和提取 HTML 數據
from bs4 import BeautifulSoup
這裏也可以直接import bs4
,但代碼中每次用的時候都要寫上包名bs4,如:bs4.BeautifulSoup 啥啥啥
而from bs4 import BeautifulSoup
是直接將BeautifulSoup
類導入到當前命名空間直接使用,不需要再帶包名。因此建議用from bs4 import BeautifulSoup
- 最後需要還需要用 urllib.request 來將網絡對象複製到本地文件
import urllib.request
感覺 urllib.request
和前面導入的 requests
有點像呀~ 查了一下資料發現是這樣:
通常而言,在我們使用python爬蟲時,更建議用requests庫,因爲requests比urllib更爲便捷,requests可以直接構造get,post請求併發起,而urllib.request只能先構造get,post請求,再發起。
但是將網絡對象複製到本地文件這個功能需要通過 urllib.request.urlretrieve()
函數來實現,所以兩個庫都導入了。
這個網頁比較簡單,導入這三個庫就夠用了~
2. 定義一個函數getMoviesImg()
① 獲取網站數據:
res = requests.get(url,params=params,headers=headers)
這樣獲取到的結果是一個 HTTP 狀態碼。
需要用.text
方法再來獲取一下這個結果裏的文本信息。
有的網站對於反爬蟲力度比較大,請求的時候可以構造一個請求頭加上,請求頭(Request Headers)在最前面開發者模式中的 Network 裏就可以找到。
今天爬取的這個頁面很簡單,就直接 GET 請求 url 即可,可以啥都不帶。
#獲取網站數據
url = requests.get('http://news.jstv.com/a/20171018/1508322421993.shtml')
#url.encoding = 'utf-8' #如果需要用到頁面中的漢字內容,則需要進行解碼,否則中文會出現亂碼
html = url.text
ps:比如這個頁面↓,百度搜索“經典電影臺詞截圖”,請求的url就是由問號 ? 前面基本的url地址和後面的一大堆參數組成的,這時候就需要用到 params 了。
② 解析網頁:
BeautifulSoup4 是將複雜HTML文檔轉換成一個複雜的樹形結構,每個節點都是Python對象,之後就可以利用 soup 加標籤名輕鬆地獲取這些標籤的內容了。
BeautifulSoup(markup,'html.parser')
- markup 是被解析的html格式的內容
- html.parser表示解析用的解析器
#解析網頁
soup = BeautifulSoup(html,'html.parser')
③ 獲取所有標籤內容:
完成了前面的工作,獲取標籤內容就變得很簡單了~
#獲取所有的img標籤
movie = soup.find_all('img')
#獲取src路徑
for i in movie:
imgsrc = i.get('src')
- 擴展一下~
bs = BeautifulSoup(html,"html.parser")
print(bs.title) # 獲取title標籤的所有內容
print(bs.title.name) # 獲取title標籤的標籤名稱
print(bs.title.string) # 獲取title標籤的文本內容
print(bs.head) # 獲取head標籤的所有內容
print(bs.div) # 獲取第一個div標籤中的所有內容
print(bs.div["id"]) # 獲取第一個div標籤的id的值
print(bs.a) # 獲取第一個a標籤的所有內容
print(bs.find_all("a")) # 獲取所有的a標籤的所有內容
print(bs.find(id="u1")) # 獲取id="u1"
for item in bs.find_all("a"):
print(item.get("href")) # 獲取所有的a標籤,並遍歷打印a標籤中的href的值
for item in bs.find_all("a"):
print(item.get_text()) # 獲取所有的a標籤,並遍歷打印a標籤的文本值
④ 將URL表示的網絡對象下載到本地:
我這裏用到的是 urlretrieve () 函數,它可以直接將遠程數據下載到本地。
urlretrieve(url, filename=None, reporthook=None, data=None)
url:外部或者本地url,url中建議不要含有中文,否則容易出錯。
finename:指定了保存本地路徑(如果參數未指定,urllib會生成一個臨時文件保存數據。)
reporthook:是一個回調函數,當連接上服務器、以及相應的數據塊傳輸完畢時會觸發該回調,我們可以利用這個回調函數來顯示當前的下載進度。
data:指 post 到服務器的數據,該方法返回一個包含兩個元素的(filename, headers)元組,filename 表示保存到本地的路徑,header 表示服務器的響應頭。
#將URL表示的網絡對象複製到本地文件
urllib.request.urlretrieve(imgsrc , filename )
第三步:執行
run run run!
(最後有個無傷大雅的小報錯,就不截圖啦)
等它都跑完就可以在指定目錄中看到網頁裏所有的圖片啦~
--------------------------------------------- 補充 ---------------------------------------------
第四步:優化一下吧
執行以後發現會存在兩個問題:
- 網頁中還有很多其它的圖片,也是放在img標籤裏的,需要把這些圖片過濾掉;
- 有一些src是空的,.urlretrieve()函數就會報錯:
ValueError: unknown url type: ''
。
想了一個比較簡單的解決辦法,就是隻下載符合要求的src鏈接。
打印出所有的 src 路徑,就會發現網頁中所有想要的圖片的鏈接路徑都是以 “http://static.jstv.com/gather/hl/20171018/” 開頭的。
這樣的話就可以用.startswith()
函數判斷之後再下載。
#判斷圖片src路徑是否以指定內容開頭(過濾頁面中的其它不想要的圖片)
if imgsrc.startswith('http://static.jstv.com/gather/hl/20171018/'):
……
改改改,runrunrun
多好看~~~
最後附上並沒有多少行的完整代碼:
import requests
import urllib.request
from bs4 import BeautifulSoup
def getMoviesImg():
url = requests.get('http://news.jstv.com/a/20171018/1508322421993.shtml')
#獲取網站數據
html = url.text
#解析網頁
soup = BeautifulSoup(html,'html.parser')
#獲取所有的img標籤
movie = soup.find_all('img')
x = 1
for i in movie:
# 獲取src路徑
imgsrc = i.get('src')
#判斷圖片src路徑是否以指定內容開頭(過濾頁面中的其它不想要的圖片)
if imgsrc.startswith('http://static.jstv.com/gather/hl/20171018/'):
# print(imgsrc)
#本地路徑
filename = 'E:/download/movie/%s.jpg'%x
#將URL表示的網絡對象複製到本地文件
urllib.request.urlretrieve(imgsrc , filename)
print('下載第%d張' % x)
x += 1
print('**下載完成!**')
getMoviesImg()
立兩個小小的flag在這裏:
- 下次想用網頁裏圖片的描述作爲對應圖片下載後的名稱。
- 以後再爬個好看的小說吧!
撒花!!!✿✿ヽ(°▽°)ノ✿