目錄
前言
當你看到這篇博客時,恭喜你被我的標題騙了進來🤪🤪 欸欸欸,別走,精彩的在下面。
本篇文章並不是什麼高大上的爬蟲教學,旨在激發一位小白的好奇心,通過本文的學習,基本可以滿足你的爬蟲小心思~
如果你是小白,這篇文章對你入坑有所幫助的話,麻煩點個贊❗
如果你是大佬,這篇文章有什麼說的不對的地方,麻煩給予指導✍
對了,本篇基於你得對所使用的語言Python有所瞭解,其次還基於你對前端三劍客HTML、CSS、JavaScript有所瞭解。如果你對上述沒有了解,你可以先去了解一下再來食用本篇文章。
其次,以下代碼我都會添加上time.sleep() 睡眠函數,目的是爲了不對目標網址造成不可逆的傷害(雖然不太可能),但是各位還是要注意,爬蟲可以,搞破壞就小心呵呵噠。
廢話不多說,我們來入坑了
爬蟲是個啥?
國際慣例,先給大家科普(雖然我很不情願,畢竟你想學這個東西,你起碼有所瞭解)
爬蟲,就是打開一個網頁,將你想要的東東下載下來。
XX:(小聲bb:這不就是鼠標點一點的事嗎,弄得這麼複雜)
這位同學,你說的沒錯,就是鼠標點一點的事,但是加入你打開了某個網站,裏面琳琅滿足的又大又白好看的圖片😍
如果用鼠標點,點一天可能才下載幾十張上百張,還有幾萬張等着你。這時候可心疼了,小孩子才選擇,我想全都要,這可咋辦?
爬蟲這時候就出來,爬蟲就是通過代碼的形式,幫你自動化的完成點擊操作,幾萬張的圖片,你要肆無忌憚(但千萬別肆無忌憚)的話一會就搞定了,然後就點開文件夾....
鋪墊知識
打開瀏覽器(建議谷歌瀏覽器),找到瀏覽器地址欄,然後在裏敲https://www.doutula.com/photo/list/,你會看到網頁內容。沒錯,今天我們就是來爬這些又大又白的表情包。(如果侵犯了鬥圖啦,聯繫我立馬更新)
我們Crtl+U,看到這些文字了嗎?這就是網頁源代碼,這纔是網頁赤裸裸的樣子。(也可以鼠標右鍵->查看網頁源代碼)
我們回到剛剛頁面,按一下F12,帶你一下彈出窗口左上角的箭頭,接着把鼠標移到你想要的圖片上,就可以找到對應的標籤。
好了,如何找到想要的東西我們就講到這,下一部分我們將編寫代碼,初步獲取到網頁的源代碼。
運行環境
首先說一下運行環境:
Windows10 我也想摸摸mac
Python3.7 推薦使用Anaconda這個管理工具,但是本篇我是不用的,避免大家的學習成本(而且Pycharm也有類似的工具)
PyCharm 2019.3.3
貼心的大暖男給你準備好了Python和PyCharm安裝包了(溫馨提示,Pycharm破解是失效的,需要自己弄)
安裝包鏈接:https://share.weiyun.com/5CMS5fx 密碼:5ct54a
Requests庫
Requests庫是python中強大的網絡請求庫,可以實現跟瀏覽器一樣發送各種HTTP請求來獲取網站的數據。
安裝:win+R 輸入cmd打開命令行窗口,輸入下面這一句
pip install requests
Requests就安裝好了,提供一份 Requests中文文檔
我們來看看如何獲取網頁源代碼
首先創建項目 quick_in_pit
創建文件 pit.py
編寫代碼
import requests # 導入requests庫
r = requests.get('https://www.doutula.com/photo/list/', ) # 像目標url地址發送get請求,返回一個response對象
print(r.text) # r.text是http response的網頁HTML
執行,發現獲取到了內容,不看內容,至少沒有報錯,證明我們是請求成功了
再來看看內容,報的是404。假裝深思熟路一會,沒想到這麼快就祭出殺手鐗了。這個網站用nginx代理,還進行了反爬操作。
(關於反爬不是我這篇要說的內容,說了我以後的素材怎麼辦?)
修改一下代碼,給我們的代碼添加上請求頭。僞造一個User-Agent
import requests # 導入requests庫
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/54.0.2840.99 Safari/537.36'}
r = requests.get('https://www.doutula.com/', headers=headers) # 像目標url地址發送get請求,返回一個response對象
print(r.text) # r.text是http response的網頁HTML
在執行一次,這次源代碼還不被我們手到擒來😤
Requests就介紹到這裏,Requests的更多使用請自己翻文檔啦,有中文還有什麼看不懂的
BeautifulSoup 庫
上一小節我們拿到了網頁的源代碼啦,那麼怎麼提取我們想要的內容呢?xi大大教我們要不忘初心,我們的初心是什麼?是又大又白的圖片!BeautifulSoup庫就是一個解析HTML文檔的庫,能夠幫助我們提取我們想要的指定標籤的內容。
安裝:
pip install beautifulsoup4
我們簡稱 beautifulsoup4 爲bs4 溫馨提供:bs4中文文檔
使用bs4 解析器推薦使用lxml,這裏使用自帶html.parser
首先我們需要定位我們要找到的圖片,還記得F12嗎?我們可以用肉眼加手定位標籤,計算機怎麼做呢?當然是根據字符,有什麼可以定位標籤的字符? 當然是標籤屬性啦,像 id、class這些,還有css選擇器,還有Xpath(強烈推薦Xpath,但是我就不告訴你)
這裏我們觀察這個標籤,發現class,這應該是所有圖片都有的class。
然後我們編寫下面代碼
import requests # 導入requests庫
import bs4
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/54.0.2840.99 Safari/537.36'}
r = requests.get('https://www.doutula.com/', headers=headers) # 像目標url地址發送get請求,返回一個response對象
#print(r.text) # r.text是http response的網頁HTML
soup = bs4.BeautifulSoup(r.text, 'html.parser')
all_img = soup.findAll('img', class_='lazy image_dtb img-responsive loaded')
for img in all_img:
print(img)
執行代碼,發現竟然什麼都沒有輸出?你們就會想立馬拉到最下面說評論說:你個大屁眼子,根本行不通。
客官別急,我們想一想,爲啥呀!再次深思熟慮後,這裏我們是對獲取到的源碼進行提取,不是網頁顯示的源碼進行提取,是不是這個網站又做了什麼手腳?我們把 print(r.txt)打開,好你的XXX,和我們網頁上看到的class進入不一樣。
修改代碼
import requests # 導入requests庫
import bs4
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/54.0.2840.99 Safari/537.36'}
r = requests.get('https://www.doutula.com/', headers=headers) # 像目標url地址發送get請求,返回一個response對象
# print(r.text) # r.text是http response的網頁HTML
soup = bs4.BeautifulSoup(r.text, 'html.parser')
all_img = soup.findAll('img', class_='img-responsive lazy image_dta')
for img in all_img:
print(img)
執行,img標籤就被我們手到擒來了。
提取到標籤,進一步提取內容,因爲我們只用src的內容呀,放心,強大的bs4就可以做到,不用學新東西了
提取屬性簡直不要太簡單,在上面基礎上,添加上['src']即可
print(img['src'])
路徑獲取到了,我們再寫一個保存就應該可以搞定了,下方高能!
import bs4
import os
import requests
import time
class BeautifulPicture:
def __init__(self): # 類的初始化操作
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/54.0.2840.99 Safari/537.36'} # 給請求指定一個請求頭來模擬chrome瀏覽器
self.web_url = 'https://www.doutula.com/photo/list/' # 要訪問的網頁地址
self.folder_path = 'D:\youDaYouBai' # 設置圖片要存放的文件目錄
def get_pic(self):
print('開始網頁get請求')
r = self.request(self.web_url)
print('開始獲取所有a標籤')
all_img = bs4.BeautifulSoup(r.text, 'html.parser').find_all('img',
class_='img-responsive lazy image_dta') # 獲取網頁中的class爲img-responsive lazy image_dta的所有img標籤
print('開始創建文件夾')
self.mkdir(self.folder_path) # 創建文件夾
print('開始切換文件夾')
os.chdir(self.folder_path) # 切換路徑至上面創建的文件夾
for img in all_img: # 循環每個標籤,獲取標籤中圖片的url並且進行網絡請求,最後保存圖片
img_src = img['data-original'] # img標籤中完整的 data-original 字符串
print('img標籤的style內容是:', img_src)
img_name = img['alt']
time.sleep(2) # 不要肆無忌憚,2s抓一張圖
self.save_img(img_src, img_name) # 調用save_img方法來保存圖片
def save_img(self, url, name): ##保存圖片
print('開始請求圖片地址,過程會有點長...')
img = self.request(url)
file_name = name + os.path.splitext(url)[-1]
print('開始保存圖片')
f = open(file_name, 'ab')
f.write(img.content)
print(file_name, '圖片保存成功!')
f.close()
def request(self, url): # 返回網頁的response
r = requests.get(url, headers=self.headers) # 像目標url地址發送get請求
return r
def mkdir(self, path): ##這個函數創建文件夾
path = path.strip()
isExists = os.path.exists(path)
if not isExists:
print('創建名字叫做', path, '的文件夾')
os.makedirs(path)
print('創建成功!')
else:
print(path, '文件夾已經存在了,不再創建')
beauty = BeautifulPicture() # 創建類的實例
beauty.get_pic() # 執行類中的方法
接着我們執行代碼。控制檯打出一系列說明,代碼正常運行。看着飛快流動的控制檯,不說了,我先去拿紙巾了.....
我回來啦
迫不及待點開文件夾一看,這都是些啥啊。我要這紙巾有何用?
沒想到這裏還有一關,再次陷入沉思,等會,我們回頭看剛剛的動圖,發現怎麼都是loader.gif?33 再回頭看看網頁源代碼,發現問題不簡單,原來真正的圖片路徑保存在 data-original 和 data-backup屬性中,這裏我想說的是 我們要學會和網站開發者鬥智鬥勇
修改代碼!
import bs4
import os
import requests
class BeautifulPicture:
def __init__(self): # 類的初始化操作
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/54.0.2840.99 Safari/537.36'} # 給請求指定一個請求頭來模擬chrome瀏覽器
self.web_url = 'https://www.doutula.com/photo/list/' # 要訪問的網頁地址
self.folder_path = 'D:\youDaYouBai' # 設置圖片要存放的文件目錄
def get_pic(self):
print('開始網頁get請求')
r = self.request(self.web_url)
print('開始獲取所有a標籤')
all_img = bs4.BeautifulSoup(r.text, 'html.parser').find_all('img',
class_='img-responsive lazy image_dta') # 獲取網頁中的class爲img-responsive lazy image_dta的所有img標籤
print('開始創建文件夾')
self.mkdir(self.folder_path) # 創建文件夾
print('開始切換文件夾')
os.chdir(self.folder_path) # 切換路徑至上面創建的文件夾
for img in all_img: # 循環每個標籤,獲取標籤中圖片的url並且進行網絡請求,最後保存圖片
img_src = img['data-original'] # img標籤中完整的 data-original 字符串
print('img標籤的style內容是:', img_src)
img_name = img['alt']
time.sleep(2) # 睡2s 不要肆無忌憚,被抓了我不負責
self.save_img(img_src, img_name) # 調用save_img方法來保存圖片
def save_img(self, url, name): ##保存圖片
print('開始請求圖片地址,過程會有點長...')
img = self.request(url)
file_name = name + os.path.splitext(url)[-1]
print('開始保存圖片')
f = open(file_name, 'ab')
f.write(img.content)
print(file_name, '圖片保存成功!')
f.close()
def request(self, url): # 返回網頁的response
r = requests.get(url, headers=self.headers) # 像目標url地址發送get請求,返回一個response對象。有沒有headers參數都可以。
return r
def mkdir(self, path): ##這個函數創建文件夾
path = path.strip()
isExists = os.path.exists(path)
if not isExists:
print('創建名字叫做', path, '的文件夾')
os.makedirs(path)
print('創建成功!')
else:
print(path, '文件夾已經存在了,不再創建')
beauty = BeautifulPicture() # 創建類的實例
beauty.get_pic() # 執行類中的方法
再跑一遍!
Wow,又白又大的表情包就被我們下載下來了。但是還有個問題!他怎麼只能保存這一頁的,我還得手動更換頁碼嗎?這裏我們下一節說
bs4當然還有很多妙用,像上面說的 css選擇器,還有Xpath ,自學纔是王道啊
PhatomJS + Selenium
上文中,我們的爬蟲面臨着一個問題,我們還是被網站識別到了我們使用爬蟲操作的,這可咋辦啊?難不成要回到起點,手動點擊?更重要的是,現在的JS技術這麼炫酷,下拉刷新,Ajax渲染,這些等頁面加載完了還得加載一堆東西的網址,單純使用request並不能滿足需求了,這可怎麼辦?
作爲推動時間發展的程序員,怎麼會被這點問題難到?沒有瀏覽器?我們就創建一個瀏覽器出來,這就是這一小節要說的PhatomJS + Selenium
PhatomJS是一個WebKit內核的瀏覽器引擎,它能像瀏覽器一樣(它就是一個瀏覽器,只不過沒有界面)解析網頁,以及運行JavaScript腳本。
Selenium是一個自動化測試框架,因爲它能夠模擬人工操作,比如能在瀏覽器中點擊按鈕、在輸入框中輸入文本、自動填充表單、還能進行瀏覽器窗口的切換、對彈出窗口進行操作。也就是說你能手動做的東西,基本都能用它來實現自動化!
聽到上面這兩句話,是不是大徹大悟,頻頻點頭,可行!Python + PhatomJS + Selenium 是爬蟲的無敵三件套。
PhatomJS 不能使用pip install 來安裝。需要去官網安裝,小暖男在這裏給你備好了,在上文的包裏面一併擁有,因爲實在是下不下來,後面用服務器weget去下載下載了一個多小時才下下來的。
下載完成的是一個壓縮包,解壓到你想存放的目錄,同時配置環境變量,沒錯又是環境變量。
只找到了英文文檔 PhatomJS 英文文檔
安裝selenium就用pip安裝就可以 Selenium中文文檔
pip install selenium
selenium也提供了對標籤進行提取的操作,我們既可以用selenium也可以繼續使用bs4,下面我使用selenium。
PhatomJS 無頁面版本已經被廢棄了,現在都推薦使用瀏覽器驅動的形式,如果我們使用PhatomJS會在控制檯輸出這樣一句話。
D:\Program Files\python3.7\lib\site-packages\selenium\webdriver\phantomjs\webdriver.py:49: UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead
warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
首先下載Chrome瀏覽器驅動:Chrome瀏覽器驅動下載地址 選擇你瀏覽器的版本,大版本要一致。選擇自己的系統版本,然後下載。這是一個壓縮包,解壓後存到一個目錄中,然後把該目錄添加到環境變量。我就直接把他放在PhatomJS 的目錄下了
查看自己版本在網址上輸入
chrome://version/
寫段代碼測試一下
from selenium import webdriver # 導入Selenium的webdriver
from selenium.webdriver.common.keys import Keys # 導入Keys
import time # 導入time控制時間
driver = webdriver.Chrome() # 指定使用的瀏覽器,初始化webdriver
driver.get("http://www.baidu.com") # 請求網頁地址
assert "百度一下" in driver.title # 看看 “百度一下” 關鍵字是否在網頁title中,如果在則繼續,如果不在,程序跳出。
elem = driver.find_element_by_name("wd") # 找到name爲wd的元素,這裏是個搜索框
elem.clear() # 清空搜索框中的內容
elem.send_keys("大誌的博客") # 在搜索框中輸入 “大誌的博客”
time.sleep(2) # 睡兩秒
elem.send_keys(Keys.RETURN) # 相當於回車鍵,提交
assert "No results found." not in driver.page_source # 如果當前頁面文本中有“No results found.”則程序跳出
time.sleep(10) # 睡10秒
driver.close() # 關閉webdriver
接下來就是改造我們上一節的項目了
首先是創建Chrome,__init__方法中追加 self.browser = webdriver.Chrome()
def __init__(self): # 類的初始化操作
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/54.0.2840.99 Safari/537.36'} # 僞造請求頭
self.web_url = 'https://www.doutula.com/photo/list/' # 要訪問的網頁地址
self.folder_path = 'D:\youDaYouBai' # 設置圖片要存放的文件目錄
self.browser = webdriver.Chrome()
接着改造get_pic 方法
首先我們要找到下一頁的按鈕,但是我們發現沒辦法太明確的獲取到這個a標籤,但是我們換個思路,這個是所有的page-link最後一個,所以我們可以這樣做。爬蟲中思路很重要。
# 先獲取所有的分頁按鈕
pages = self.browser.find_elements_by_class_name("page-link")
# 最後一個就是下一頁 這裏並沒有做最後一頁的判斷 可以用一個current 來比較
next_page = pages[len(pages) - 1]
接着是遞歸到下一頁,很簡單,我們修改web_url,遞歸調用get_pic()方法即可。這裏我只抓取前三頁。
# 獲取href路徑
next_page_href = next_page.get_attribute("href")
# 只抓取前三頁的內容,不要太肆無忌憚了。
if int(next_page_href[-1]) > 3:
print("抓取完成")
self.browser.close()
exit()
# 這裏開始遞歸獲取下一頁
# 設置訪問路徑
time.sleep(5) # 每抓一頁 睡五秒
self.web_url = next_page_href
self.get_pic()
我們看看效果
拉取圖片中:
切換下一頁,注意url和刷新
附上究極形態源碼:
import os
import requests
from selenium import webdriver # 導入Selenium的webdriver
import time
class BeautifulPicture:
def __init__(self): # 類的初始化操作
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/54.0.2840.99 Safari/537.36'} # 僞造請求頭
self.web_url = 'https://www.doutula.com/photo/list/' # 要訪問的網頁地址
self.folder_path = 'D:\youDaYouBai' # 設置圖片要存放的文件目錄
self.browser = webdriver.Chrome()
def get_pic(self):
print('開始網頁get請求')
self.browser.get(self.web_url)
# selenium 獲取標籤 classname是用 . 間隔的
all_img = self.browser.find_elements_by_class_name(
"img-responsive.lazy.image_dta.loaded")
if (len(all_img)) < 1:
print("沒有獲取到圖片,程序退出")
self.browser.close()
exit()
# 先獲取所有的分頁按鈕
pages = self.browser.find_elements_by_class_name("page-link")
# 最後一個就是下一頁 這裏並沒有做最後一頁的判斷 可以用一個current 來比較
next_page = pages[len(pages) - 1]
print('開始創建文件夾')
self.mkdir(self.folder_path) # 創建文件夾
print('開始切換文件夾')
os.chdir(self.folder_path) # 切換路徑至上面創建的文件夾
for img in all_img: # 循環每個標籤,獲取標籤中圖片的url並且進行網絡請求,最後保存圖片
img_src = img.get_attribute('data-original') # img標籤中data-original完整的字符串
print('img標籤的style內容是:', img_src)
img_name = img.get_attribute('alt')
time.sleep(1) # 1秒抓一張圖,不要太肆無忌憚了
self.save_img(img_src, img_name) # 調用save_img方法來保存圖片
# 獲取href路徑
next_page_href = next_page.get_attribute("href")
# 只抓取前三頁的內容,不要太肆無忌憚了。
if int(next_page_href[-1]) > 3:
print("抓取完成")
self.browser.close()
exit()
# 這裏開始遞歸獲取下一頁
# 設置訪問路徑
time.sleep(5) # 每抓一頁 睡五秒
self.web_url = next_page_href
self.get_pic()
def save_img(self, url, name): ##保存圖片
print('開始請求圖片地址,過程會有點長...')
img = requests.get(url, headers=self.headers)
file_name = name + os.path.splitext(url)[-1]
print('開始保存圖片')
f = open(file_name, 'ab')
f.write(img.content)
print(file_name, '圖片保存成功!')
f.close()
def mkdir(self, path): ##這個函數創建文件夾
path = path.strip()
isExists = os.path.exists(path)
if not isExists:
print('創建名字叫做', path, '的文件夾')
os.makedirs(path)
print('創建成功!')
else:
print(path, '文件夾已經存在了,不再創建')
beauty = BeautifulPicture() # 創建類的實例
beauty.get_pic() # 執行類中的方法
最後,希望這篇文章能夠激起你的興趣。上述講的可以滿足我們的大多數需求,但還有很多優秀的技術框架,還有反爬以及避免被封殺等操作,這些都不是重點,
記住,技術本身是無罪的,有罪的在於濫用技術的人
我去鬥圖了,我們下次再見~
有什麼問題可以評論或者私信我,每日在線解(LIAO)疑(SAO)。
我是大誌,一位準備996的卑微碼農🐶,覺得好用記得點贊收藏!!!