所謂爬蟲,就是幫助咱們從互聯網上獲取相關數據並提取有用的信息。在大數據時代,爬蟲是數據採集很是重要的一種手段,比人工進行查詢,採集數據更加方便,更加快捷。剛開始學爬蟲時,通常從靜態,結構比較規範的網頁入手,而後逐步深刻。今天以爬取豆瓣最受關注圖書爲例,簡述Python在爬蟲方面的初步應用,僅供學習分享使用,若有不足之處,還請指正。html
若是要實現爬蟲,須要掌握的Pyhton相關知識點以下所示:python
本例中爬取的信息爲豆瓣最受關注圖書榜信息,共10本當前最受歡迎圖書。正則表達式
爬取頁面URL【Uniform Resource Locator,統一資源定位器】:https://book.douban.com/chart?subcat=F數據庫
爬取頁面截圖,以下所示:json
經過瀏覽器提供的開發人員工具(快捷鍵:F12),能夠方便的對頁面元素進行定位,通過定位分析,本次所要獲取的內容,包括在UL【class=chart-dashed-list】標籤內容,每一本書,都對應一個LI元素,是本次爬取的目標,以下所示:瀏覽器
每一本書,對應一個Li【class=media clearfix】元素,書名爲對應a【class=fleft】元素,描述爲P【class=subject-abstract color-gray】標籤元素內容,具體到每一本書的的詳細內容,以下所示:服務器
若是要分析數據,首先要進行下載,獲取要爬取的數據信息,在Python中爬取數據,主要用requests模塊,以下所示:網絡
1 def get_data(url): 2 """ 3 獲取數據 4 :param url: 請求網址 5 :return:返回請求的頁面內容 6 """ 7 # 請求頭,模擬瀏覽器,不然請求會返回418 8 header = { 9 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 10 'Chrome/70.0.3538.102 Safari/537.36 Edge/18.18363'} 11 resp = requests.get(url=url, headers=header) # 發送請求 12 if resp.status_code == 200: 13 # 若是返回成功,則返回內容 14 return resp.text 15 else: 16 # 不然,打印錯誤狀態碼,並返回空 17 print('返回狀態碼:', resp.status_code) 18 return ''
注意:在剛開始寫爬蟲時,一般會遇到「HTTP Error 418」,請求網站的服務器端會進行檢測這次訪問是否是人爲經過瀏覽器訪問,若是不是,則返回418錯誤碼。檢測請求頭是常見的反爬蟲策略,所爲爲了模擬瀏覽器訪問,須要構造請求Header,而後便可正常訪問。app
正常瀏覽器訪問成功的狀態碼爲200,及請求標頭中User-Agent。以下所示:ide
當獲取到數據後,須要進行數據分析,才能獲得想要的內容。requests模塊獲取到的內容爲Html源碼字符串,能夠經過BeautifulSoup裝載成對象,而後進行數據獲取,以下所示:
1 def parse_data(html: str = None): 2 """ 3 解析數據 4 :param html: 5 :return:返回書籍信息列表 6 """ 7 bs = BeautifulSoup(html, features='html.parser') # 轉換頁面內容爲BeautifulSoup對象 8 ul = bs.find(name='ul', attrs={'class': 'chart-dashed-list'}) # 獲取列表的父級內容 9 lis = ul.find_all('li', attrs={'class': re.compile('^media clearfix')}) # 獲取圖書列表 10 books = [] # 定義圖書列表 11 for li in lis: 12 # 循環遍歷列表 13 strong_num = li.find(name='strong', attrs={'class': 'fleft green-num-box'}) # 獲取書籍排名標籤 14 book_num = strong_num.text # 編號 15 h2_a = li.find(name='a', attrs={'class': 'fleft'}) # 獲取書名標籤 16 book_name = h2_a.text # 獲取書名 17 p_info = li.find(name='p', attrs={'class': "subject-abstract color-gray"}) # 書籍說明段落標籤 18 19 book_info_str = p_info.text.strip() # 獲取書籍說明,並 去先後空格 20 # book_info_list = book_info_str.split('/', -1) # 分隔符 21 books.append( 22 {'book_num': book_num, 'book_name': book_name, 'book_info': book_info_str}) # 將內容添加到列表 23 24 return books
解析到目標數據後,須要進行數據持久化,以便後續進一步分析。持久化一般能夠保存到數據庫中,本例爲了簡單,保存到本地json文件中,以下所示:
1 def save_data(res_list): 2 """ 3 保存數據 4 :param res_list: 保存的內容文件 5 :return: 6 """ 7 with open('books.json', 'w', encoding='utf-8') as f: 8 res_list_json = json.dumps(res_list, ensure_ascii=False) 9 f.write(res_list_json)
本例完整代碼,以下所示:
1 import json # json 包,用於讀取解析,生成json格式的文件內容 2 import requests # 請求包 用於發起網絡請求 3 from bs4 import BeautifulSoup # 解析頁面內容幫助包 4 import re # 正則表達式 5 6 7 def get_data(url): 8 """ 9 獲取數據 10 :param url: 請求網址 11 :return:返回請求的頁面內容 12 """ 13 # 請求頭,模擬瀏覽器,不然請求會返回418 14 header = { 15 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 16 'Chrome/70.0.3538.102 Safari/537.36 Edge/18.18363'} 17 resp = requests.get(url=url, headers=header) # 發送請求 18 if resp.status_code == 200: 19 # 若是返回成功,則返回內容 20 return resp.text 21 else: 22 # 不然,打印錯誤狀態碼,並返回空 23 print('返回狀態碼:', resp.status_code) 24 return '' 25 26 27 def parse_data(html: str = None): 28 """ 29 解析數據 30 :param html: 31 :return:返回書籍信息列表 32 """ 33 bs = BeautifulSoup(html, features='html.parser') # 轉換頁面內容爲BeautifulSoup對象 34 ul = bs.find(name='ul', attrs={'class': 'chart-dashed-list'}) # 獲取列表的父級內容 35 lis = ul.find_all('li', attrs={'class': re.compile('^media clearfix')}) # 獲取圖書列表 36 books = [] # 定義圖書列表 37 for li in lis: 38 # 循環遍歷列表 39 strong_num = li.find(name='strong', attrs={'class': 'fleft green-num-box'}) # 獲取書籍排名標籤 40 book_num = strong_num.text # 編號 41 h2_a = li.find(name='a', attrs={'class': 'fleft'}) # 獲取書名標籤 42 book_name = h2_a.text # 獲取書名 43 p_info = li.find(name='p', attrs={'class': "subject-abstract color-gray"}) # 書籍說明段落標籤 44 45 book_info_str = p_info.text.strip() # 獲取書籍說明,並 去先後空格 46 # book_info_list = book_info_str.split('/', -1) # 分隔符 47 books.append( 48 {'book_num': book_num, 'book_name': book_name, 'book_info': book_info_str}) # 將內容添加到列表 49 50 return books 51 52 53 def save_data(res_list): 54 """ 55 保存數據 56 :param res_list: 保存的內容文件 57 :return: 58 """ 59 with open('books.json', 'w', encoding='utf-8') as f: 60 res_list_json = json.dumps(res_list, ensure_ascii=False) 61 f.write(res_list_json) 62 63 64 # 開始執行,調用函數 65 url = 'https://book.douban.com/chart?subcat=F' 66 html = get_data(url=url) # 獲取數據 67 books = parse_data(html) # 解析數據 68 save_data(books) # 保存數據 69 print('done')
本例爬取內容,保存到books.json文件中,以下所示:
1 [ 2 { 3 "book_num": "1", 4 "book_name": "心靈偵探城塚翡翠", 5 "book_info": "相澤沙呼 / 2021-4 / 人民文學出版社 / 79.00元 / 精裝" 6 }, 7 { 8 "book_num": "2", 9 "book_name": "平原上的摩西", 10 "book_info": "雙雪濤 / 2021-4 / 北京日報出版社 / 59 / 精裝" 11 }, 12 { 13 "book_num": "3", 14 "book_name": "眩暈", 15 "book_info": "[德國] 溫弗裏德·塞巴爾德 / 2021-4 / 廣西師範大學出版社 / 52.00元 / 精裝" 16 }, 17 { 18 "book_num": "4", 19 "book_name": "一把刀,千個字", 20 "book_info": "王安憶 / 2021-4 / 人民文學出版社 / 精裝" 21 }, 22 { 23 "book_num": "5", 24 "book_name": "字母表謎案", 25 "book_info": "大山誠一郎 / 2021-5 / 河南文藝出版社 / 42.00 / 平裝" 26 }, 27 { 28 "book_num": "6", 29 "book_name": "星之繼承者", 30 "book_info": "[英] 詹姆斯·P.霍根 / 2021-4 / 新星出版社 / 58.00元 / 精裝" 31 }, 32 { 33 "book_num": "7", 34 "book_name": "美麗黑暗", 35 "book_info": "[法] 法比安·韋爾曼 編 / [法] 凱拉斯科多 繪 / 2021-4 / 後浪丨中國紡織出版社 / 88.00元 / 精裝" 36 }, 37 { 38 "book_num": "8", 39 "book_name": "心", 40 "book_info": "[日] 夏目漱石 / 2021-3-30 / 江蘇鳳凰文藝出版社 / 45.00元 / 精裝" 41 }, 42 { 43 "book_num": "9", 44 "book_name": "奇蹟唱片行", 45 "book_info": "[英] 蕾秋·喬伊斯 / 2021-6-11 / 北京聯合出版公司 / 48 / 平裝" 46 }, 47 { 48 "book_num": "10", 49 "book_name": "派對恐懼症", 50 "book_info": "[美]卡門•瑪麗亞•馬查多 / 2021-5 / 世紀文景/上海人民出版社 / 59.00元 / 精裝" 51 } 52 ]
望嶽
唐·杜甫