這次爬取一點有意思的東西,爬豆瓣美女網站
1.爬取目標
本次爬蟲比較簡單,先只爬取豆瓣美女網站中的“大胸妹”tab,而且只爬取最外層的圖片,不點開圖集,如下
2.分析網頁元素
網頁原始碼如下
可以看到很明顯的規律,每個圖片都包裹在<img>標籤中,而且title屬性代表名稱,src屬性代表圖片url
所以本次爬蟲就提取上述2個元素:alt和src
可以用BeautifulSoup或者正規表示式進行提取
3.爬取過程
先貼出完整程式碼,再進行分析
# -*- coding:utf-8 -*- import requests from requests.exceptions import RequestException from bs4 import BeautifulSoup import bs4 import os def get_html(url, header=None): """請求初始url""" response = requests.get(url, headers=header) try: if response.status_code == 200: # print(response.status_code) # print(response.text) return response.text return None except RequestException: print("請求失敗") return None def parse_html(html, list_data): """提取img的名稱和圖片url,並將名稱和圖片地址以字典形式返回""" soup = BeautifulSoup(html, 'html.parser') img = soup.find_all('img') for t in img: if isinstance(t, bs4.element.Tag): # print(t) name = t.get('alt') img_src = t.get('src') list_data.append([name, img_src]) dict_data = dict(list_data) return dict_data def get_image_content(url): """請求圖片url,返回二進位制內容""" print("正在下載", url) try: r = requests.get(url) if r.status_code == 200: return r.content return None except RequestException: return None def main(num=None, depth=None): base_url = 'https://www.dbmeinv.com/index.htm?' for i in range(1, depth): url = base_url + 'cid=' + str(num) + '&' + 'pager_offset=' + str(i) # print(url) header = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q = 0.9, image/webp,image/apng,*/*;q=' '0.8', 'Accept-Encoding': 'gzip,deflate,br', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Cache-Control': 'max-age=0', 'Connection': 'keep-alive', 'Host': 'www.dbmeinv.com', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0(WindowsNT6.1;Win64;x64) AppleWebKit/537.36(KHTML, likeGecko) Chrome/' '70.0.3538.102Safari/537.36 ' } list_data = [] html = get_html(url) # print(html) dictdata = parse_html(html, list_data) # print(list_data) # print(dict(list_data)) # print(data) # for url in data.values(): # download_image(url) root_dir = os.path.dirname(os.path.abspath('.')) save_path = root_dir + '/pics/' for t in dictdata.items(): file_path = '{0}/{1}.{2}'.format(save_path, t[0], 'jpg') if not os.path.exists(file_path): # 判斷是否存在檔案,不存在則爬取 with open(file_path, 'wb') as f: f.write(get_image_content(t[1])) f.close() print('檔案儲存成功') if __name__ == '__main__': # t = main(2) # print(t) # 這樣列印之所以為None,是因為main函式中沒有任何內容返回出來,尷尬了。。。 main(2, 10)
(1)構造url
“大胸妹”首頁url為:https://www.dbmeinv.com/index.htm?cid=2
翻到下一頁後,變為:https://www.dbmeinv.com/index.htm?cid=2&pager_offset=2
可以看到有2個引數cid和pager_offset
所在在主函式中,定義了2個引數,一個表示“大胸妹”對應的cid值,一個表示翻頁
def main(num=None, depth=None): base_url = 'https://www.dbmeinv.com/index.htm?' for i in range(1, depth): url = base_url + 'cid=' + str(num) + '&' + 'pager_offset=' + str(i)
(2)分析parse_html()方法
這個方法用來提取圖片的title和src,使用的是BeautifulSoup;
傳入2個引數,一個是初始url的返回內容,另外定義了一個list_data這裡表示一個列表,會把提取到的title和src,以[title:src]的形式追加到list_data中;
然後再把list_data轉換為字典返回出去,這樣就得到了一個以title為鍵,以src為值的字典。
後面可以通過迭代這個字典,在儲存圖片時,使用圖片的title作為圖片名稱
列印list_data和dict_data分別如下
(3)根據parse_html()方法得到圖片url後,還需要進一步請求圖片url,並將返回的二進位制內容以jpg的格式進行儲存
首先定義了一個get_image_content()方法,它與get_html()方法一樣,不過是返回的二進位制內容
然後就是主函式中構造圖片儲存的形式了:
因為parse_html()方法返回了dict_data,它是以title為鍵,以src為值的字典,
我們知道迭代字典,可以得到一個鍵值對組成的元組,如下:
所以可以通過迭代這個字典,分別提取字典的鍵作為圖片名稱,提取字典值作為圖片url進行請求,如下:
root_dir = os.path.dirname(os.path.abspath('.')) save_path = root_dir + '/pics/' for t in dictdata.items(): file_path = '{0}/{1}.{2}'.format(save_path, t[0], 'jpg') if not os.path.exists(file_path): # 判斷是否存在檔案,不存在則爬取 with open(file_path, 'wb') as f: f.write(get_image_content(t[1])) f.close() print('檔案儲存成功')
t[0]表示每個鍵值對的鍵,即圖片的title;t[1]表示每個鍵值對的值,即圖片的url
最終儲存的圖片如下
補充:用正則提取
import re import requests import os from requests.exceptions import RequestException r = requests.get('https://www.dbmeinv.com/index.htm?cid=2') # print(r.status_code) html = r.text # print(r.text) # print(html) name_pattern = re.compile(r'<img class="height_min".*?title="(.*?)"', re.S) src_pattern = re.compile(r'<img class="height_min".*?src="(.*?.jpg)"', re.S) name = name_pattern.findall(html) # 提取title src = src_pattern.findall(html) # 提取src data = [name,src] # print(name) # print(src) d=[] for i in range(len(name)): # print(name[i]) # print(src[i]) d.append([name[i], src[i]]) dictdata = dict(d) for i in dictdata.items(): print(i) def get_content(url): try: r = requests.get(url) if r.status_code == 200: return r.content return None except RequestException: return None root_dir = os.path.dirname(os.path.abspath('.')) save_path = root_dir + '/pics/' for t in dictdata.items(): file_path = '{0}/{1}.{2}'.format(save_path, t[0], 'jpg') if not os.path.exists(file_path): # 判斷是否存在檔案,不存在則爬取 with open(file_path, 'wb') as f: f.write(get_content(t[1])) f.close() print('檔案儲存成功')