錄一下爬取豆瓣熱門專欄的經(jīng)過,通過這篇文章,你能學(xué)會requests,HTMLParser,json的基本使用,以及爬取網(wǎng)頁內(nèi)容的基本思路。
使用模塊
1,獲取豆瓣首頁代碼:首先我們需要訪問豆瓣頁面,獲取首頁的源碼。這里推薦使用第三方庫:requests,相比python內(nèi)置的 urllib 模塊,requests使用起來更簡單,功能更全面
2,對獲取的代碼進(jìn)行解析:對于解析html代碼,已經(jīng)有很多功能強(qiáng)大的框架能使用,如Scrapy,PySpider,Beautiful Soup等,這里我們只是學(xué)習(xí)下爬蟲的基本使用,所以內(nèi)建的 HTMLParser 足夠使用了
3,對獲取的數(shù)據(jù)進(jìn)行處理: json
思路分析
既然我們需要的只是熱門專欄模塊的數(shù)據(jù),那么我們需要一個標(biāo)志來告訴我們:下面的代碼就是專欄模塊了,準(zhǔn)備獲取數(shù)據(jù)。同樣我們需要知道當(dāng)前
讀取的是圖片、標(biāo)題還是欄目類別,以此將數(shù)據(jù)儲存到相應(yīng)的字段中。總的來說,我們最起碼應(yīng)該通過代碼來實(shí)現(xiàn)以下幾點(diǎn):
1,獲取網(wǎng)頁源碼
2,通過自定義方法解析html
3,通過標(biāo)志位判斷當(dāng)前數(shù)據(jù)是否是我們需要的數(shù)據(jù)
4,通過分析代碼結(jié)構(gòu)決定將要儲存的數(shù)據(jù)結(jié)構(gòu)
5,將數(shù)據(jù)按照特定格式進(jìn)行本地儲存
豆瓣官網(wǎng):https://www.douban.com/,分析一下我們需要爬取模塊的代碼:
可以看到,我們需要爬取的數(shù)據(jù)都在 ul.time-list 這個代碼塊里,那么我們的標(biāo)志位就是:當(dāng)開始標(biāo)簽為 ul并且具有類名 time-list時,我們就要獲取數(shù)據(jù)了,當(dāng)結(jié)束標(biāo)簽為 ul 時,停止解析,繼續(xù)分析代碼結(jié)構(gòu),每個 li 里面包含了對應(yīng)數(shù)據(jù)里面的 詳情頁跳轉(zhuǎn)鏈接,圖片地址,標(biāo)題以及專欄類別,那么我們的數(shù)據(jù)結(jié)構(gòu)到這里也就很清楚了:一個 li 塊對應(yīng)一條數(shù)據(jù),每條數(shù)據(jù)由四個字段組成:
詳情頁跳轉(zhuǎn)鏈接 href --> 這里我們考慮了一下, 還是通過第二個a標(biāo)簽來獲取,它具有統(tǒng)一的類名title,同時我們還能獲取 標(biāo)題title,
圖片地址 imgUrl --> 通過每個li代碼塊里面唯一img標(biāo)簽的src屬性可以輕松獲取,
標(biāo)題 title --> 通過 a.title獲取,
專欄類別 type --> 唯一的 span 標(biāo)簽獲取
tip:像上面我們選取數(shù)據(jù)的標(biāo)志位一樣,img的alt可以獲取標(biāo)題,a標(biāo)簽的文本也可以獲取標(biāo)題,兩個a標(biāo)簽都能獲取跳轉(zhuǎn)鏈接不管是爬蟲還是平時其他的開發(fā),我們經(jīng)常會遇到,同一個需求有多種方法實(shí)現(xiàn),這時候我們就需要思考一下哪一種方法更簡潔,冷靜分析后的編碼不一定最優(yōu)秀,但自己肯定印象深刻(說遠(yuǎn)了,回歸正題)。
編碼實(shí)現(xiàn)
通過上面的準(zhǔn)備工作,我們已經(jīng)確定了需要引入的模塊,解析事件觸發(fā)標(biāo)志位,需要獲取的數(shù)據(jù),儲存的數(shù)據(jù)結(jié)構(gòu),可以正式開始編碼了:
requests是第三方庫,需要另外安裝,其他的是內(nèi)置模塊,直接引入即可:
1 import requests 2 from html.parser import HTMLParser 3 from html.entities import name2codepoint 4 import json
獲取豆瓣首頁源碼:
1 r=requests.get('https://www.douban.com/', timeout=3)
是的,通過 requests獲取網(wǎng)頁只需要一行代碼,timeout為獲取頁面超時時間,通過 r.text 就是我們需要的html源碼,r.encoding可以獲取網(wǎng)頁編碼格式,當(dāng)然requests還有其他的方法供我們使用,
如 帶參數(shù)的url: r=requests.get(url, params={.....}),獲取數(shù)據(jù)等
解析豆瓣首頁源碼:
HTMLParser 里已經(jīng)封裝好了針對html的各種事件處理,如 開始標(biāo)簽,結(jié)束標(biāo)簽,標(biāo)簽屬性,標(biāo)簽文本,注釋,特殊字符,不了解的可以看下這個:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017784593019776,很簡單很清晰
1 class MyHTMLParser(HTMLParser): 2 def __init__(self): 3 super().__init__() 4 # 是否開始解析 5 self._allowRun=False 6 7 # 創(chuàng)建dist備用:儲存數(shù)據(jù) 8 self.hotList={'data': []} 9 10 # 每一個 li 塊數(shù)據(jù)儲存 11 self.listItem={} 12 13 # 當(dāng)前解析標(biāo)簽類型的標(biāo)志位 14 self.tagType='' 15 16 # 開始標(biāo)簽及 標(biāo)簽屬性 17 def handle_starttag(self, tag, attrs): 18 if tag=='ul' and ('class', 'time-list') in attrs: 19 self._allowRun=True 20 21 # 若當(dāng)前是開啟解析狀態(tài) 22 if self._allowRun: 23 if tag=='a' and ('class', 'title') in attrs: 24 self.tagType='a' 25 for (key, value) in attrs: 26 if key=='href': 27 self.listItem[key]=value 28 if tag=='img': 29 for (key, value) in attrs: 30 if key=='src': 31 self.listItem['imgUrl']=value 32 33 if tag=='span': 34 self.tagType='span' 35 36 # 結(jié)束標(biāo)簽 37 def handle_endtag(self, tag): 38 self.tagType='' 39 if tag=='ul': 40 self._allowRun=False 41 42 if tag=='li': 43 if len(self.listItem) !=0: 44 self.hotList['data'].append(self.listItem) 45 self.listItem={} 46 47 # 空標(biāo)簽及 標(biāo)簽屬性 48 def handle_startendtag(self, tag, attrs): 49 if self._allowRun: 50 if tag=='img': 51 for (key, value) in attrs: 52 if key=='src': 53 self.listItem['imgUrl']=value 54 55 # 標(biāo)簽文本 56 def handle_data(self, data): 57 if self._allowRun: 58 if self.tagType=='a': 59 self.listItem['title']=data 60 self.taga=False 61 elif self.tagType=='span': 62 self.listItem['type']=data 63 64 # 注釋 65 def handle_comment(self, data): 66 pass 67 68 # HTML entity 字符 69 def handle_entityref(self, name): 70 pass 71 72 # Numeric 字符 73 def handle_charref(self, name): 74 pass 75 76 parser=MyHTMLParser() 77 parser.feed(r.text)
代碼說明:我們必須知道在解析過程中,實(shí)例方法是按照源碼順序循環(huán)執(zhí)行的,也就是說在同一個實(shí)例方法里,我們可以針對不同的標(biāo)簽或其他條件來進(jìn)行不同的操作。我們所有的解析操作都是針對 ul.time-list 代碼塊的,所以我們需要一個開關(guān),當(dāng)前代碼是 ul.time-list時才執(zhí)行我們自定義的解析操作,這個開關(guān)就是上面代碼里的 _allowRun,當(dāng)開始標(biāo)簽是 ul.time-list的是否為 True,當(dāng)結(jié)束標(biāo)簽是 ul 的是否為False,而只有當(dāng) _allowRun 為 True的時候,我們才繼續(xù)解析當(dāng)前的標(biāo)簽是 a 還是 img 或者 span。由于我們要在 文本解析事件 handle_data 中獲取 a 標(biāo)簽的文本作為字段 title 的值,span標(biāo)簽的文本作為字段 type 的值,所以我們需要一個標(biāo)志位變量來供我們在執(zhí)行 handle_data 的時候判斷當(dāng)前解析的文本是屬于 a 還是 span,這個標(biāo)志位變量就是上面代碼中 tagType,在 handle_starttag 中賦值,在 handle_endtag 中清空。我們將每一條數(shù)據(jù)儲存在 listItem 中,當(dāng)結(jié)束標(biāo)簽為 li 時,說明我們的對一個 li 代碼塊解析完畢,listItem 儲存了我們需要的單挑數(shù)據(jù),將 listItem 添加到 hotList中并清空 listItem 。執(zhí)行上面代碼,我們已經(jīng)將數(shù)據(jù)儲存在實(shí)例屬性 hotList里面,我們可以在終端輸出 parser.hotList:
儲存數(shù)據(jù)
接下來就是將數(shù)據(jù)儲存到本地文件中,而寫入數(shù)據(jù)也是非常簡單:
1 with open('hotList.json', 'w') as f: 2 json.dump(parser.hotList, f)
在當(dāng)前目錄里打開 hotList.json 文件,可以看到如下數(shù)據(jù):
數(shù)據(jù)倒是寫入了,但是中文卻沒有如愿顯示,而且對于追求美觀的我們來說也無法接受,所以我們需要指定寫入編碼格式,以及格式化:
1 with open('hotList.json', 'w', encoding="utf-8") as f: 2 json.dump(parser.hotList, f, ensure_ascii=False, indent=4)
我們在寫入的時候指定編碼格式為 utf-8: encoding="utf-8",在 json.dump寫入數(shù)據(jù)時增加了兩個參數(shù):ensure_ascii=False 禁止進(jìn)行 ascii轉(zhuǎn)碼,indent=4:按縮進(jìn)為 4個單位格式化數(shù)據(jù),當(dāng)然我們還可以將字段進(jìn)行排序,只需要加上字段:sort_keys=True,按需選擇即可,再打開 hotList.json 文件查看:
1 { 2 "data": [ 3 { 4 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/1c6e77ec-c493-11e9-84c0-0242ac110008.jpg", 5 "href": "https://m.douban.com/time/column/164?dt_time_source=douban-web_anonymous", 6 "title": "傷別離與共春風(fēng)——唐宋詞的情感世界", 7 "type": "音頻專欄" 8 }, 9 { 10 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/511ccf86-b8fc-11e9-b188-0242ac110008.jpg", 11 "href": "https://m.douban.com/time/column/163?dt_time_source=douban-web_anonymous", 12 "title": "世界記憶大師教你快速提升記憶力", 13 "type": "視頻專欄" 14 }, 15 { 16 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/74897a9e-880c-11e9-bd82-0242ac11001b.jpg", 17 "href": "https://m.douban.com/time/column/159?dt_time_source=douban-web_anonymous", 18 "title": "黑白之間:二十八堂書法練習(xí)課", 19 "type": "視頻專欄" 20 }, 21 { 22 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/6f488990-a773-11e9-b587-0242ac110011.jpg", 23 "href": "https://m.douban.com/time/column/161?dt_time_source=douban-web_anonymous", 24 "title": "馬伯庸的冷門書單", 25 "type": "音頻專欄" 26 }, 27 { 28 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/6c46cb9c-ac61-11e9-97e2-0242ac11000c.jpg", 29 "href": "https://m.douban.com/time/column/162?dt_time_source=douban-web_anonymous", 30 "title": "聽!解說式音樂會——古典音樂聆聽指南", 31 "type": "視頻專欄" 32 }, 33 { 34 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/ebd421cc-9968-11e9-ad2c-0242ac110006.jpg", 35 "href": "https://m.douban.com/time/column/158?dt_time_source=douban-web_anonymous", 36 "title": "從格里菲斯到諾蘭——影迷都在看的電影結(jié)構(gòu)大師課", 37 "type": "視頻專欄" 38 }, 39 { 40 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/fa83f054-9633-11e9-a82e-0242ac110006.jpg", 41 "href": "https://m.douban.com/time/column/157?dt_time_source=douban-web_anonymous", 42 "title": "打開電影聲音的魔盒——好萊塢聲音設(shè)計(jì)大師課", 43 "type": "視頻專欄" 44 }, 45 { 46 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/81788c8e-8e53-11e9-b51e-0242ac110010.jpg", 47 "href": "https://m.douban.com/time/column/156?dt_time_source=douban-web_anonymous", 48 "title": "一劇之本——好萊塢編劇教父大師課", 49 "type": "視頻專欄" 50 }, 51 { 52 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/5d7d70aa-8b25-11e9-a08f-0242ac110012.jpg", 53 "href": "https://m.douban.com/time/column/155?dt_time_source=douban-web_anonymous", 54 "title": "老葉說電影——90分鐘看懂中國電影產(chǎn)業(yè)", 55 "type": "視頻專欄" 56 }, 57 { 58 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/e2e59078-828e-11e9-a465-0242ac110012.jpg", 59 "href": "https://m.douban.com/time/column/154?dt_time_source=douban-web_anonymous", 60 "title": "好萊塢特效大師課——從概念藝術(shù)到3D建模", 61 "type": "視頻專欄" 62 } 63 ] 64 }
這樣就只有兩個字:噓服。
總結(jié)
這個例子只是用來熟悉爬蟲基本操作和思維邏輯,真正用到項(xiàng)目中還是得結(jié)合其他框架,如 Beautiful Soup,就可以獲取指定代碼片段進(jìn)行解析而不需要像我們上面那樣設(shè)置開關(guān)或標(biāo)志位。有興趣的朋友可以自己動手試試。
文的文字及圖片來源于網(wǎng)絡(luò),僅供學(xué)習(xí)、交流使用,不具有任何商業(yè)用途,如有問題請及時聯(lián)系我們以作處理
題目:根據(jù)豆瓣讀書top250,根據(jù)出版社對書籍?dāng)?shù)量分類,繪制餅圖
import scrapy
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#terminal 終端實(shí)現(xiàn)
cd .. # 跳轉(zhuǎn)到上一層目錄
scrapy startproject booktop # 和項(xiàng)目同名的scrapy框架項(xiàng)目
ROBOTSTXT_OBEY=False # 君子協(xié)議 false 不遵守
USER_AGENT='Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'
DOWNLOAD_DELAY=0.5 # 下載延遲## 如何改變文本的樣式
#spiders文件夾下創(chuàng)建python文件 bookspider.py
import scrapy
from booktop.items import BookItem
class BookSpider(scrapy.Spider):
name="bookspider"
allowed_domains=['book.douban.com']
start_urls=['https://book.douban.com/top250']
def parse(self, response, **kwargs):
print(response.text) # 測試頁面
測試:
#在terminal終端進(jìn)行
cd booktop # 進(jìn)入項(xiàng)目文件夾
scrapy crawl bookspider # 運(yùn)行項(xiàng)目下的爬蟲(和name的值保持一致)
# 測試成功,看到頁面代碼
需要導(dǎo)入BookItem類 文件開頭導(dǎo)入 from booktop.items import BookItem
def parse(self, response, **kwargs):
#print(response.text)
# table 一個table一本書
tables=response.xpath('//table') # css也可以
# print('書籍個數(shù)',len(tables))
# print(tables)
for t in tables:
#提取 extract()[0]
tit=t.css('div.pl2 a::attr(title)').extract()[0]
# print(title) 書名
pu=t.css('p.pl::text').extract()[0]
pu=pu.split('/')[-3].strip()
#print(pub) 出版社
yield BookItem(title=tit,pub=pu)
需要使用item對象完成數(shù)據(jù)封裝并傳輸
#items.py書寫書類
class BookItem(scrapy.Item):
#define the fields for your item here like:
title=scrapy.Field()
pub=scrapy.Field()
pass
# 在setting文件下,解開注釋
ITEM_PIPELINES={
'booktop.pipelines.BooktopPipeline': 300,
}
數(shù)據(jù)存儲到txt文件下
# 打開管道文件 BooktopPipeline
class BooktopPipeline:
def process_item(self, item, spider):
# 編碼格式設(shè)置為utf-8
file=open('result.txt','a+',encoding='utf-8')
file.write(item['title']+','+item['pub']+'\n')
return item
# 運(yùn)行測試結(jié)果result.txt下有數(shù)據(jù)成功
# 在項(xiàng)目中創(chuàng)建 分析文件 demo1.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
# 處理中文字體
font={'family': 'microsoft yahei',
'weight': 'bold',
'size': 12}
matplotlib.rc('font',**font)
# 讀取文件
df=pd.read_csv('result.txt',names=['title','pub'])
# print(df)
# 福爾摩斯探案集 出版社有問題,手動修改
df.loc[8,'pub']='群眾出版社'
# print(df)
# 按出版社不同分類匯總書數(shù)量,取出前5名
result=df['pub'].value_counts().head()
print(result)
plt.pie(result,labels=result.index,autopct='%3.1f%%')
plt.show()
私信小編01即可獲取大量Python學(xué)習(xí)資料
在當(dāng)今數(shù)字化時代,對電影的評價和反饋在很大程度上影響著人們的選擇。豆瓣作為一個知名的電影評價平臺,匯集了大量用戶對電影的評論和評分。本文將介紹如何使用Python編寫爬蟲來獲取豆瓣電影的影評數(shù)據(jù),并通過情感分析對評論進(jìn)行簡單的情感評價。
在開始之前,我們需要安裝一些Python庫來幫助我們完成這項(xiàng)任務(wù):
我們首先需要確定要爬取的電影和其對應(yīng)的豆瓣鏈接。以電影《肖申克的救贖》為例,其豆瓣鏈接為:https://movie.douban.com/subject/1292052/。我們將使用Python編寫爬蟲來獲取該電影的影評數(shù)據(jù)。
pythonimport requests
from bs4 import BeautifulSoup
import pandas as pd
# 發(fā)送HTTP請求獲取網(wǎng)頁內(nèi)容
url='https://movie.douban.com/subject/1292052/comments?status=P'
response=requests.get(url)
html_content=response.text
# 使用Beautiful Soup解析HTML內(nèi)容
soup=BeautifulSoup(html_content, 'html.parser')
# 提取影評信息
comments=[]
for comment in soup.find_all(class_='comment-item'):
username=comment.find(class_='comment-info').a.text.strip()
rating=comment.find(class_='rating').attrs['title'].strip()
content=comment.find(class_='short').text.strip()
comments.append({'用戶名': username, '評分': rating, '評論內(nèi)容': content})
# 將數(shù)據(jù)轉(zhuǎn)換為DataFrame
df=pd.DataFrame(comments)
print(df)
以上代碼會輸出一個DataFrame,其中包含了《肖申克的救贖》的影評數(shù)據(jù),包括用戶名、評分和評論內(nèi)容。
接下來,我們將使用TextBlob庫進(jìn)行簡單的情感分析,對評論進(jìn)行情感評價。
pythonfrom textblob import TextBlob
# 對評論進(jìn)行情感分析
df['情感分析']=df['評論內(nèi)容'].apply(lambda x: TextBlob(x).sentiment.polarity)
# 打印情感分析結(jié)果
print(df)
通過情感分析,我們可以得到每條評論的情感分?jǐn)?shù),從-1到1,其中-1表示負(fù)面情感,0表示中性,1表示積極情感。
通過本文的介紹,我們了解了如何使用Python編寫爬蟲來獲取豆瓣電影的影評數(shù)據(jù),并通過情感分析對評論進(jìn)行簡單的情感評價。這項(xiàng)技術(shù)可以幫助大家更好地了解用戶對電影的反饋和評價,為電影選擇提供參考。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。