《零基礎入門學習Python》第056講:論一隻爬蟲的自我修養4:網路爬圖
今天我們結合前面學習的知識,進行一個例項,從網路上下載圖片,話說我們平時閒來無事會上煎蛋網看看新鮮事,那麼,熟悉煎蛋網的朋友一定知道,這裡有一個 隨手拍 的欄目,我們今天就來寫一個爬蟲,自動抓取每天更新的 隨手拍。
要寫爬蟲,首先要做的第一件事就是踩點,主動發現網頁之間的規律,還有圖片連結之間有什麼規律,例如說,該網站的連結形式為:http://jandan.net/ooxx/page-‘頁碼數’#comments,(頁碼數應該小於等於當天的頁碼數(即目前最大頁碼數)),
1.那我們怎樣獲取目前最大的頁碼數呢(最新頁碼),我們在頁碼[77]這個位置點選右鍵,審查元素,看到了:<span class="current-comment-page">[77]</span>
我們完全可以通過搜尋 current-comment-page 在後面偏移 3 位就可以得到 77 這個最新的頁面,因為你不能去輸入一個具體的數字,因為這裡的數字每天都會改變。
2.我們在圖片的位置點選右鍵,審查元素,發現了圖片的地址,都是來自於新浪,然後都在 img 標籤裡,我們就可以使用 img src 作為關鍵詞來進行查詢,搜尋到了圖片的地址就可以參照我們之前下載一隻貓的例子了。把下面圖片的地址用 urlopen() 開啟,然後將其 save 到一個檔案裡去(二進位制),就可以了。
<img src="http://ww3.sinaimg.cn/mw600/006XNEY7gy1fy62ba9d6cj30u00u0x6p.jpg" style="max-width: 480px; max-height: 750px;">
我們弄清楚了以上幾點,就可以開始寫我們的爬蟲程式啦.....
(我們抓取前10頁的圖片,儲存到指定的本地資料夾中)
下面是老師講的程式碼:
#從煎蛋網的隨手拍欄目下載圖片 import urllib.request import os import random def url_open(url): req = urllib.request.Request(url) req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36') #使用代理(就加入下面五行) #proxies = ['119.6.144.70:81', '111.1.36.9:80', '203.144.144.162:8080'] #proxy = random.choice(proxies) #proxy_support = urllib.request.ProxyHandler({'http':proxy}) #opener = urllib.request.build_opener(proxy_support) #urllib.request.install_opener(opener) response = urllib.request.urlopen(url) html = response.read() return html def get_page(url): #得到最新頁面的頁碼數 html = url_open(url) html = html.decode('utf-8') #因為要以字串的形式查詢,所以要 decode #然後就是查詢 html 中的 'current-comment-page' a = html.find( 'current-comment-page') + 23 #加上 23 位偏移就剛到到頁碼數的第一位數字 b = html.find(']', a) #找到 a 位置之後的第一個方括號所在位置的索引座標 return html[a : b] #這就是最新的頁碼數啦 def find_imgs(url): #給一個頁面的連結,返回所有圖片地址組成的列表 html = url_open(url).decode('utf-8') img_addrs = [] #宣告一個儲存圖片地址的列表 #查詢圖片地址 a = html.find('img src=') while a != -1: b = html.find('.jpg', a, a+255) #在 a 到 a+255 區間找 '.jpg',防止有不是 '.jpg' 格式的圖片 #如果 b 找不到,b 就返回 -1 if b != -1: img_addrs.append(html[a+9: b+4]) else: b = a + 9 a = html.find('img src=', b) return img_addrs def save_imgs(folder, img_addrs): for each in img_addrs: filename = each.split('/')[-1] with open(filename, 'wb') as f: img = url_open(each) f.write(img) def download_figures(folder = 'figures', page = 10): os.mkdir(folder) #建立資料夾 os.chdir(folder) url = "http://jandan.net/ooxx/" #隨手拍欄目的連結,也是最新頁面的連結 page_num = int(get_page(url)) #得到最新頁面的頁碼數 for i in range(page): page_url = url + 'page-' + str(page_num) + '#comments' #得到要爬取的頁面的連結 print(page_url) img_addrs = find_imgs(page_url) #得到頁面所有圖片的地址,儲存為列表 save_imgs(folder, img_addrs) #儲存圖片到本地資料夾 page_num -= 1 #逐步找到前幾個頁面 if __name__ == '__main__': download_figures()
但是現在,煎蛋網用這段程式碼是無法實現的了,主要問題在於 沒有辦法爬取到 .jpg,這是因為這個網站已經被加密了。
怎樣判斷一個網站被加密了,就是
使用urllib.urlopen匯出html文字和審查元素中相應欄位對不上。
以後你會發現對不上是常態,一般是JS加密的 可以說大一點的網站這些資訊都會對不上。
那怎麼解決呢?
目前我只用的一種方法就是:使用selenium爬取js加密的網頁
需要詳細講解的可以檢視:python使用selenium爬取js加密的網頁
所以呢,我的程式碼就是下面這樣子了:
#從加密的煎蛋網的隨手拍欄目下載圖片
import os
from selenium import webdriver
import urllib.request
def url_open(url): #返回普通不加密網頁的原始碼(速度快)
req = urllib.request.Request(url)
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36')
response = urllib.request.urlopen(url)
html = response.read()
return html
def url_open_jm(url): #返回加密網頁的原始碼(速度慢)
chrome = webdriver.Chrome()
chrome.get(url)
html = chrome.page_source
return html #返回的就是字串
'''
def get_page(url): #得到最新頁面的頁碼數(可以使用不加密讀碼得到,為了加快速度)
html = url_open(url)
#然後就是查詢 html 中的 'current-comment-page'
a = html.find( 'current-comment-page') + 23 #加上 23 位偏移就剛到到頁碼數的第一位數字
b = html.find(']', a) #找到 a 位置之後的第一個方括號所在位置的索引座標
return html[a : b] #這就是最新的頁碼數啦
'''
def get_page(url): #得到最新頁面的頁碼數
html = url_open(url)
html = html.decode('utf-8') #因為要以字串的形式查詢,所以要 decode
#然後就是查詢 html 中的 'current-comment-page'
a = html.find( 'current-comment-page') + 23 #加上 23 位偏移就剛到到頁碼數的第一位數字
b = html.find(']', a) #找到 a 位置之後的第一個方括號所在位置的索引座標
return html[a : b] #這就是最新的頁碼數啦
def find_imgs(url): #給一個頁面的連結,返回所有圖片地址組成的列表
html = url_open_jm(url) #這個必須使用加密開啟的方式
img_addrs = [] #宣告一個儲存圖片地址的列表
#查詢圖片地址
#加密的網頁破解後得到的影象在這裡:
#<img src="http://ww3.sinaimg.cn/mw600/006XNEY7gy1fy66dacugfj30qh0zkdhu.jpg"
#所以要先找jpg,然後找img src=
a = html.find('.jpg')
while a != -1:
b = html.rfind('img src=', a-100, a) #在 a-100 到 a區間找 'img src=',必須反向查詢
#如果 b 找不到,b 就返回 -1
if b != -1:
img_addrs.append(html[b+9: a+4])
a = html.find('.jpg', a+4)
for each in img_addrs:
print(each)
return img_addrs
def save_imgs(folder, img_addrs):
for each in img_addrs:
filename = each.split('/')[-1]
with open(filename, 'wb') as f:
img = url_open(each)
f.write(img)
def download_figures(folder = 'figures', page = 2):
os.mkdir(folder) #建立資料夾
os.chdir(folder)
url = "http://jandan.net/ooxx/" #隨手拍欄目的連結,也是最新頁面的連結
page_num = int(get_page(url)) #得到最新頁面的頁碼數
for i in range(page):
page_url = url + 'page-' + str(page_num) + '#comments' #得到要爬取的頁面的連結
print(page_url)
img_addrs = find_imgs(page_url) #得到頁面所有圖片的地址,儲存為列表
save_imgs(folder, img_addrs) #儲存圖片到本地資料夾
page_num -= 1 #逐步找到前幾個頁面
if __name__ == '__main__':
download_figures()