溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

發(fā)布時間:2023-04-12 10:02:38 來源:億速云 閱讀:121 作者:iii 欄目:編程語言

這篇“Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化”文章吧。

線程

進(jìn)程:進(jìn)程是代碼在數(shù)據(jù)集合上的一次運行活動,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位。

線程:是輕量級的進(jìn)程,是程序執(zhí)行的最小單元,是進(jìn)程的一個執(zhí)行路徑。

一個進(jìn)程中至少有一個線程,進(jìn)程中的多個線程共享進(jìn)程的資源。

線程生命周期

在創(chuàng)建多線程之前,我們先來學(xué)習(xí)一下線程生命周期,如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

由圖可知,線程可以分為五個狀態(tài)——新建、就緒、運行、阻塞、終止。

首先新建一個線程并開啟線程后線程進(jìn)入就緒狀態(tài),就緒狀態(tài)的線程不會馬上運行,要獲得CPU資源才會進(jìn)入運行狀態(tài),在進(jìn)入運行狀態(tài)后,線程有可能會失去CPU資源或者遇到休眠、io操作(讀寫等操作)線程進(jìn)入就緒狀態(tài)或者阻塞狀態(tài),要等休眠、io操作結(jié)束或者重新獲得CPU資源后,才會進(jìn)入運行狀態(tài),等到運行完后進(jìn)入終止?fàn)顟B(tài)。

注意:新建線程系統(tǒng)是需要分配資源的,終止線程系統(tǒng)是需要回收資源的,那么如何減去新建/終止線程的系統(tǒng)開銷呢,這時我們可以創(chuàng)建線程池來重用線程,這樣就可以減少系統(tǒng)的開銷了。

在創(chuàng)建線程池之前,我們先來學(xué)習(xí)如何創(chuàng)建多線程。

創(chuàng)建多線程

創(chuàng)建多線程可以分為四步:

  1. 創(chuàng)建函數(shù);

  2. 創(chuàng)建線程;

  3. 啟動線程;

  4. 等待結(jié)束;

創(chuàng)建函數(shù)

為了方便演示,我們拿博客園的網(wǎng)頁做爬蟲函數(shù),具體代碼如下所示:

import requests
urls=[
 f'https://www.cnblogs.com/#p{page}'
 for page in range(1,50)
]
def get_parse(url):
 response=requests.get(url)
print(url,len(response.text))

首先導(dǎo)入requests網(wǎng)絡(luò)請求庫,把我們所有的要爬取的URL保存在列表中,然后自定義函數(shù)get_parse來發(fā)送網(wǎng)絡(luò)請求、打印請求的URL和響應(yīng)的字符長度。

創(chuàng)建線程

在上一步我們創(chuàng)建了爬蟲函數(shù),接下來將創(chuàng)建線程了,具體代碼如下所示:

import threading
#多線程
def multi_thread():
 threads=[]
 for url in urls:
 threads.append(
 threading.Thread(target=get_parse,args=(url,))
 )

首先我們導(dǎo)入threading模塊,自定義multi_thread函數(shù),再創(chuàng)建一個空列表threads來存放線程任務(wù),通過threading.Thread()方法來創(chuàng)建線程。其中:

  • target為運行函數(shù);

  • args為運行函數(shù)所需的參數(shù)。

注意args中的參數(shù)要以元組的方式傳入,然后通過.append()方法把線程添加到threads空列表中。

啟動線程

線程已經(jīng)創(chuàng)建好了,接下來將啟動線程了,啟動線程很簡單,具體代碼如下所示:

for thread in threads:
 thread.start()

首先我們通過for循環(huán)把threads列表中的線程任務(wù)獲取下來,通過.start()來啟動線程。

等待結(jié)束

啟動線程后,接下來將等待線程結(jié)束,具體代碼如下所示:

for thread in threads:
 thread.join()

和啟動線程一樣,先通過for循環(huán)把threads列表中的線程任務(wù)獲取下來,再使用.join()方法等待線程結(jié)束。

多線程已經(jīng)創(chuàng)建好了,接下來將測試一下多線程的速度如何,具體代碼如下所示:

if __name__ == '__main__':
t1=time.time()
 multi_thread()
 t2=time.time()
 print(t2-t1)

運行結(jié)果如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

多線程爬取50個博客園網(wǎng)頁只要1秒多,而且多線程的發(fā)送網(wǎng)絡(luò)請求的URL是隨機的。

我們來測試一下單線程的運行時間,具體代碼如下所示:

if __name__ == '__main__':
 t1=time.time()
 for i in urls:
 get_parse(i)
 t2=time.time()
 print(t2-t1)

運行結(jié)果如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

單線程爬取50個博客園網(wǎng)頁用了9秒多,單線程的發(fā)送網(wǎng)絡(luò)請求的URL是按順序的。

在上面我們說了,新建線程系統(tǒng)是需要分配資源的,終止線程系統(tǒng)是需要回收資源的,為了減少系統(tǒng)的開銷,我們可以創(chuàng)建線程池。

線程池原理

一個線程池由兩部分組成,如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

  • 線程池:里面提前建好N個線程,這些都會被重復(fù)利用;

  • 任務(wù)隊列:當(dāng)有新任務(wù)的時候,會把任務(wù)放在任務(wù)隊列中。

當(dāng)任務(wù)隊列里有任務(wù)時,線程池的線程會從任務(wù)隊列中取出任務(wù)并執(zhí)行,執(zhí)行完任務(wù)后,線程會執(zhí)行下一個任務(wù),直到?jīng)]有任務(wù)執(zhí)行后,線程會回到線程池中等待任務(wù)。

使用線程池可以處理突發(fā)性大量請求或需要大量線程完成任務(wù)(處理時間較短的任務(wù))。

好了,了解了線程池原理后,我們開始創(chuàng)建線程池。

線程池創(chuàng)建

Python提供了ThreadPoolExecutor類來創(chuàng)建線程池,其語法如下所示:

ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())

其中:

  • max_workers:最大線程數(shù);

  • thread_name_prefix:允許用戶控制由線程池創(chuàng)建的threading.Thread工作線程名稱以方便調(diào)試;

  • initializer:是在每個工作者線程開始處調(diào)用的一個可選可調(diào)用對象;

  • initargs:傳遞給初始化器的元組參數(shù)。

注意:在啟動 max_workers 個工作線程之前也會重用空閑的工作線程。

在ThreadPoolExecutor類中提供了map()和submit()函數(shù)來插入任務(wù)隊列。其中:

map()函數(shù)

map()語法格式為:

map(調(diào)用方法,參數(shù)隊列)

具體示例如下所示:

import requestsimport concurrent.futuresimport timeurls=[f'https://www.cnblogs.com/#p{page}'for page in range(1,50)]def get_parse(url):response=requests.get(url)return response.textdef map_pool():with concurrent.futures.ThreadPoolExecutor(max_workers=20) as pool:htmls=pool.map(get_parse,urls)htmls=list(zip(urls,htmls))for url,html in htmls:print(url,len(html))if __name__ == '__main__':t1=time.time()map_pool()t2=time.time()print(t2-t1)

首先我們導(dǎo)入requests網(wǎng)絡(luò)請求庫、concurrent.futures模塊,把所有的URL放在urls列表中,然后自定義get_parse()方法來返回網(wǎng)絡(luò)請求返回的數(shù)據(jù),再自定義map_pool()方法來創(chuàng)建代理池,其中代理池的最大max_workers為20,調(diào)用map()方法把網(wǎng)絡(luò)請求任務(wù)放在任務(wù)隊列中,在把返回的數(shù)據(jù)和URL合并為元組,并放在htmls列表中。

運行結(jié)果如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

可以發(fā)現(xiàn)map()函數(shù)返回的結(jié)果和傳入的參數(shù)順序是對應(yīng)的。

注意:當(dāng)我們直接在自定義方法get_parse()中打印結(jié)果時,打印結(jié)果是亂序的。

submit()函數(shù)

submit()函數(shù)語法格式如下:

submit(調(diào)用方法,參數(shù))

具體示例如下:

def submit_pool():with concurrent.futures.ThreadPoolExecutor(max_workers=20)as pool:futuress=[pool.submit(get_parse,url)for url in urls]futures=zip(urls,futuress)for url,future in futures:print(url,len(future.result()))

運行結(jié)果如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

注意:submit()函數(shù)輸出結(jié)果需需要調(diào)用result()方法。

好了,線程知識就學(xué)到這里了,接下來開始我們的爬蟲。

爬前分析

首先我們進(jìn)入同程旅行的景點網(wǎng)頁并打開開發(fā)者工具,如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

經(jīng)過尋找,我們發(fā)現(xiàn)各個景點的基礎(chǔ)信息(詳情頁URL、景點id等)都存放在下圖的URL鏈接中,

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

其URL鏈接為:

https://www.ly.com/scenery/NewSearchList.aspx?&action=getlist&page=2&kw=&pid=6&cid=80&cyid=0&sort=&isnow=0&spType=&lbtypes=&IsNJL=0&classify=0&grade=&dctrack=1%CB%871629537670551030%CB%8720%CB%873%CB%872557287248299209%CB%870&iid=0.6901326566387387

經(jīng)過增刪改查操作,我們可以把該URL簡化為:

https://www.ly.com/scenery/NewSearchList.aspx?&action=getlist&page=1&pid=6&cid=80&cyid=0&isnow=0&IsNJL=0

其中page為我們翻頁的重要參數(shù)。

打開該URL鏈接,如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

通過上面的URL鏈接,我們可以獲取到很多景點的基礎(chǔ)信息,隨機打開一個景點的詳情網(wǎng)頁并打開開發(fā)者模式,經(jīng)過查找,評論數(shù)據(jù)存放在如下圖的URL鏈接中,

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

其URL鏈接如下所示:

https://www.ly.com/scenery/AjaxHelper/DianPingAjax.aspx?action=GetDianPingList&sid=12851&page=1&pageSize=10&labId=1&sort=0&iid=0.48901069375088

其中:action、labId、iid、sort為常量,sid是景點的id,page控制翻頁,pageSize是每頁獲取的數(shù)據(jù)量。

在上上步中,我們知道景點id的存放位置,那么構(gòu)造評論數(shù)據(jù)的URL就很簡單了。

實戰(zhàn)演練

這次我們爬蟲步驟是:

  1. 獲取景點基本信息

  2. 獲取評論數(shù)據(jù)

  3. 創(chuàng)建MySQL數(shù)據(jù)庫

  4. 保存數(shù)據(jù)

  5. 創(chuàng)建線程池

  6. 數(shù)據(jù)分析

獲取景點基本信息

首先我們先獲取景點的名字、id、價格、特色、地點和等級,主要代碼如下所示:

def get_parse(url):response=requests.get(url,headers=headers)Xpath=parsel.Selector(response.text)data=Xpath.xpath('/html/body/div')for i in data:Scenery_data={'title':i.xpath('./div/div[1]/div[1]/dl/dt/a/text()').extract_first(),'sid':i.xpath('//div[@]/div/@sid').extract_first(),'Grade':i.xpath('./div/div[1]/div[1]/dl/dd[1]/span/text()').extract_first(), 'Detailed_address':i.xpath('./div/div[1]/div[1]/dl/dd[2]/p/text()').extract_first().replace('地址:',''),'characteristic':i.xpath('./div/div[1]/div[1]/dl/dd[3]/p/text()').extract_first(),'price':i.xpath('./div/div[1]/div[2]/div[1]/span/b/text()').extract_first(),'place':i.xpath('./div/div[1]/div[1]/dl/dd[2]/p/text()').extract_first().replace('地址:','')[6:8]}

首先自定義方法get_parse()來發(fā)送網(wǎng)絡(luò)請求后使用parsel.Selector()方法來解析響應(yīng)的文本數(shù)據(jù),然后通過xpath來獲取數(shù)據(jù)。

獲取評論數(shù)據(jù)

獲取景點基本信息后,接下來通過景點基本信息中的sid來構(gòu)造評論信息的URL鏈接,主要代碼如下所示:

def get_data(Scenery_data):for i in range(1,3):link = f'https://www.ly.com/scenery/AjaxHelper/DianPingAjax.aspx?action=GetDianPingList&sid={Scenery_data["sid"]}&page={i}&pageSize=100&labId=1&sort=0&iid=0.20105777381446832'response=requests.get(link,headers=headers)Json=response.json()commtent_detailed=Json.get('dpList')# 有評論數(shù)據(jù)if commtent_detailed!=None:for i in commtent_detailed:Comment_information={'dptitle':Scenery_data['title'],'dpContent':i.get('dpContent'),'dpDate':i.get('dpDate')[5:7],'lineAccess':i.get('lineAccess')}#沒有評論數(shù)據(jù)elif commtent_detailed==None:Comment_information={'dptitle':Scenery_data['title'],'dpContent':'沒有評論','dpDate':'沒有評論','lineAccess':'沒有評論'}

首先自定義方法get_data()并傳入剛才獲取的景點基礎(chǔ)信息數(shù)據(jù),然后通過景點基礎(chǔ)信息的sid來構(gòu)造評論數(shù)據(jù)的URL鏈接,當(dāng)在構(gòu)造評論數(shù)據(jù)的URL時,需要設(shè)置pageSize和page這兩個變量來獲取多條評論和進(jìn)行翻頁,構(gòu)造URL鏈接后就發(fā)送網(wǎng)絡(luò)請求。

這里需要注意的是:有些景點是沒有評論,所以我們需要通過if語句來進(jìn)行設(shè)置。

創(chuàng)建MySQL數(shù)據(jù)庫

這次我們把數(shù)據(jù)存放在MySQL數(shù)據(jù)庫中,由于數(shù)據(jù)比較多,所以我們把數(shù)據(jù)分為兩種數(shù)據(jù)表,一種是景點基礎(chǔ)信息表,一種是景點評論數(shù)據(jù)表,主要代碼如下所示:

#創(chuàng)建數(shù)據(jù)庫def create_db():db=pymysql.connect(host=host,user=user,passwd=passwd,port=port)cursor=db.cursor()sql='create database if not exists commtent default character set utf8'cursor.execute(sql)db.close()create_table()#創(chuàng)建景點信息數(shù)據(jù)表def create_table():db=pymysql.connect(host=host,user=user,passwd=passwd,port=port,db='commtent')cursor=db.cursor()sql = 'create table if not exists Scenic_spot_data (title varchar(255) not null, link varchar(255) not null,Grade varchar(255) not null, Detailed_address varchar(255) not null, characteristic varchar(255)not null, price int not null, place varchar(255) not null)'cursor.execute(sql)db.close()

首先我們調(diào)用pymysql.connect()方法來連接數(shù)據(jù)庫,通過.cursor()獲取游標(biāo),再通過.execute()方法執(zhí)行單條的sql語句,執(zhí)行成功后返回受影響的行數(shù),然后關(guān)閉數(shù)據(jù)庫連接,最后調(diào)用自定義方法create_table()來創(chuàng)建景點信息數(shù)據(jù)表。

這里我們只給出了創(chuàng)建景點信息數(shù)據(jù)表的代碼,因為創(chuàng)建數(shù)據(jù)表只是sql這條語句稍微有點不同,其他都一樣,大家可以參考這代碼來創(chuàng)建各個景點評論數(shù)據(jù)表。

保存數(shù)據(jù)

創(chuàng)建好數(shù)據(jù)庫和數(shù)據(jù)表后,接下來就要保存數(shù)據(jù)了,主要代碼如下所示:

首先我們調(diào)用pymysql.connect()方法來連接數(shù)據(jù)庫,通過.cursor()獲取游標(biāo),再通過.execute()方法執(zhí)行單條的sql語句,執(zhí)行成功后返回受影響的行數(shù),使用了try-except語句,當(dāng)保存的數(shù)據(jù)不成功,就調(diào)用rollback()方法,撤消當(dāng)前事務(wù)中所做的所有更改,并釋放此連接對象當(dāng)前使用的任何數(shù)據(jù)庫鎖。

#保存景點數(shù)據(jù)到景點數(shù)據(jù)表中def saving_scenery_data(srr):db = pymysql.connect(host=host, user=user, password=passwd, port=port, db='commtent')cursor = db.cursor()sql = 'insert into Scenic_spot_data(title, link, Grade, Detailed_address, characteristic,price,place) values(%s,%s,%s,%s,%s,%s,%s)'try:cursor.execute(sql, srr)db.commit()except:db.rollback()db.close()

注意:srr是傳入的景點信息數(shù)據(jù)。

創(chuàng)建線程池

好了,單線程爬蟲已經(jīng)寫好了,接下來將創(chuàng)建一個函數(shù)來創(chuàng)建我們的線程池,使單線程爬蟲變?yōu)槎嗑€程,主要代碼如下所示:

urls = [f'https://www.ly.com/scenery/NewSearchList.aspx?&action=getlist&page={i}&pid=6&cid=80&cyid=0&isnow=0&IsNJL=0'for i in range(1, 6)]def multi_thread():with concurrent.futures.ThreadPoolExecutor(max_workers=8)as pool:h=pool.map(get_parse,urls)if __name__ == '__main__':create_db()multi_thread()

創(chuàng)建線程池的代碼很簡單就一個with語句和調(diào)用map()方法

運行結(jié)果如下圖所示:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

好了,數(shù)據(jù)已經(jīng)獲取到了,接下來將進(jìn)行數(shù)據(jù)分析。

數(shù)據(jù)可視化

首先我們來分析一下各個景點那個月份游玩的人數(shù)最多,這樣我們就不用擔(dān)心去游玩的時機不對了。

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

我們發(fā)現(xiàn)10月、2月、1月去廣州長隆飛鳥樂園游玩的人數(shù)占總體比例最多。分析完月份后,我們來看看評論情況如何:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

可以發(fā)現(xiàn)去好評占了絕大部分,可以說:去長隆飛鳥樂園玩耍,去了都說好??戳嗽u論情況,評論內(nèi)容有什么:

Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化

以上就是關(guān)于“Python怎么獲取旅游景點信息及評論并作詞云、數(shù)據(jù)可視化”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI