python 輿情分析 nlp主題分析 (1) 待續
參考資料:https://blog.csdn.net/Eastmount/article/details/50891162 # 該博主有很多篇幅,解釋演算法原理,演算法應用。
需求:一直想試試大資料+輿情分析,雖然資料量不是很大,大概應用一下,看看是否能從海量資料中,提取出主題思想,以看看當前的輿論導向。
具體應用案例:
微博熱門話題:#中印雙方達成五點共識# 閱讀量2.4億,討論7430條。
1、資料採集,使用python+selenium,採集該話題下的博文及作者資訊,以及每個博文下的評論及作者資訊;
2、資料預處理,採用Jieba庫,構建使用者詞典,以達到更好的分詞;情感分析,採用snownlp庫,尋找政治類積極和負面詞向量做一個訓練,再進行評論分類;
3、對博文及評論作者資訊進行分析,檢視調查主體的使用者類別概況;
4、lda主題分析,對博文做主題分析,依據top3主題關鍵字,對博文群主類看法進行分析;對正、負向評論做一次主題分析,並分別分析觀點;
本編主要先完成第一步,後續再繼續更新。
1、開啟瀏覽器,手工登入微博,這裡因為微博登入太嚴格(需要簡訊驗證才能登入),所以直接人工登入。
%%time # 配置瀏覽器 options = webdriver.ChromeOptions() # 此步驟很重要,設定為開發者模式,防止被各大網站識別出來使用了Selenium options.add_experimental_option('excludeSwitches', ['enable-automation']) # 進入網頁 browser = webdriver.Chrome(options=options) wait = WebDriverWait(browser,2) browser.get('https://s.weibo.com/weibo?q=%23%E4%B8%AD%E5%8D%B0%E5%8F%8C%E6%96%B9%E8%BE%BE%E6%88%90%E4%BA%94%E7%82%B9%E5%85%B1%E8%AF%86%23')
2.1、分析微博頁面,在博文頁可以發現,是分頁展示,下一頁需要通過點選下一頁進入。博文內容在'//div[@class="card"]'中。此處需要獲取作者名稱、作者主頁連結、博文內容、博文url(為下一步獲取評論準備)、發表日期、收藏、轉發、評論、點贊數目。
%%time list_ct = [] # 儲存文章內容 while True: # 掃描文章內容,掃描一頁,判斷是否還有下一頁 wait.until(EC.presence_of_element_located((By.XPATH,'//div[@class="card"]/div[@class="card-feed"]/div[@class="content"]'))) # 獲取博文列表 list_el = browser.find_elements_by_xpath('//div[@class="card"]') try: for l in list_el: actor_url = actor_name = content = content_url =content_date = sg = zf = pl = dz = '' try: # 獲取作者 t = l.find_element_by_xpath('./div[@class="card-feed"]/div[@class="content"]/div[@class="info"]/div[2]/a') actor_url = t.get_attribute('href') actor_name = t.text # 博文內容 t = l.find_elements_by_xpath('./div[@class="card-feed"]/div[@class="content"]/p[@class="txt"]') if len(t) > 1: content = t[1].get_attribute('innerText') else: content = t[0].get_attribute('innerText') # 博文連結 t = l.find_element_by_xpath('./div[@class="card-feed"]/div[@class="content"]/p[@class="from"]/a') content_url = t.get_attribute('href') content_date = t.text # 收藏、轉發、評論、點贊 t = l.find_elements_by_xpath('./div[@class="card-act"]/ul/li') sg = t[0].get_attribute('innerText') zf = t[1].get_attribute('innerText') pl = t[2].get_attribute('innerText') dz = t[3].get_attribute('innerText') except Exception as e: pass # 追加 list_ct.append([actor_url , actor_name , content , content_url,content_date,sg , zf , pl , dz ]) # 輸出當前頁碼 try: t = browser.find_element_by_xpath('//a[@class="pagenum"]') print('掃描進行到',str(t.text)) except : pass # 判斷是否還有下一頁 #break try: t = browser.find_element_by_xpath('//div[@class="m-page"]/div/a[@class="next"]') # 點選下一頁 t.click() except: print('文章掃描結束') break except Exception as e: print('非正常結束:',str(e))
2.2將資料暫存到excel
%%time # 儲存發表的文章,到excel df = pd.DataFrame(list_ct, columns=['actor_url' , 'actor_name' , 'content' , 'content_url','content_date','sg' , 'zf','pl','dz']) # 去重 df.drop_duplicates(subset=['actor_url' , 'actor_name' , 'content' , 'content_url','content_date','sg' , 'zf','pl','dz'],inplace = True) with pd.ExcelWriter(r'../data/npl_asan/wenzhangs.xlsx') as writer: df.to_excel(writer,index=False,sheet_name = 'Sheet1')
3、通過博文連結,進入到博文主頁,分析頁面資訊,內容需要ajax非同步更新,1、需要不斷下拉進度條到底部重新整理,並點選“檢視更多”;2、某些評論回覆的會摺疊,需要不斷點選檢視更多評論。綜上所述,先下拉到最底部,再逐個點選評論顯示,最後讀取所有評論。
# # 處理評論的內容 # def deal_comment_content(content): rel = content = content.replace(":",":") if content.find(':回覆') != -1: lt = content.split(':',2) rel = lt[len(lt)-1] else: lt = content.split(':',1) rel = lt[len(lt)-1] return rel # 獲取WB_text內容 def get_comment_data(l): actor = actor_url = render = render_url = content = date = '' # 獲取發表者 t = l.find_element_by_xpath('./div[@class="WB_text"]/a[1]') actor_url = t.get_attribute('href') actor = t.text # 判斷是否回覆的評論 try: t = l.find_element_by_xpath('./div[@class="WB_text"]/a[@render="ext"]') render_url = t.get_attribute('href') render = t.text except NoSuchElementException: pass # 讀取評論內容 t = l.find_element_by_xpath('./div[@class="WB_text"]') content = t.text content = deal_comment_content(content) # 讀取評論日期 t = l.find_element_by_xpath('./div[@class="WB_func clearfix"]/div[@class="WB_from S_txt2"]') date = t.text return [actor , actor_url , render , render_url , content,date] # 滾動到最底部 def scroll_down(): while True: sh1 = browser.execute_script("return document.body.scrollHeight;") browser.execute_script('window.scrollTo(0,document.body.scrollHeight)') time.sleep(0.5) sh2 = browser.execute_script("return document.body.scrollHeight;") if sh1 == sh2: break # 載入更多評論 def loading_all_comment(): # 執行到最下,等待檢視更多 while True: scroll_down() try: morr_btn = wait.until(EC.presence_of_element_located((By.XPATH,'//span[@class="more_txt"]'))) # 如果超時 morr_btn.click() except: #print('執行到最底部') break # 載入所有子評論 def loading_all_child_comment(): while True: btns = browser.find_elements_by_xpath('//a[@action-type="click_more_child_comment_big"]') if len(btns) == 0: break for btn in btns: try: #browser.execute_script("arguments[0].click();", btn) ActionChains(browser).move_to_element(btn).click(btn).perform() # 需要移動到該控制元件,點選才有效 #btn.click() time.sleep(0.5) except: # 存在點了以後還沒載入完的,直接忽略錯誤 pass
%%time # 完整版執行 err_url = [] list_comment = [] for index, r in df.iterrows(): url = r.content_url #url = df.loc[2,'content_url'] print('序號:',str(index),'開始執行:',url) browser.get(url) try: loading_all_comment() # 載入所有評論 loading_all_child_comment() # 載入所有子評論 print('開啟所有評論') #等待內容 wait.until(EC.presence_of_element_located((By.XPATH,'//div[@node-type="root_comment"]/div[@class="list_con"]'))) list_el = browser.find_elements_by_xpath('//div[@node-type="root_comment"]/div[@class="list_con"]') # 遍歷 for l in list_el: # 獲取博文資訊 c = get_comment_data(l) list_comment.append(c) # 獲取博文評論資訊 list_child = l.find_elements_by_xpath('.//div[@node-type="child_comment"]//div[@class="list_con"]') for lc in list_child: c = get_comment_data(lc) list_comment.append(c) except TimeoutException: print('TimeoutException:',url) except NoSuchElementException: print('NoSuchElementException:',url) except: print('something wring:',url) err_url.append(url) #break
最後輸出到檔案:
%%time # 儲存評論到excel df = pd.DataFrame(list_comment, columns=['actor' , 'actor_url' , 'render' , 'render_url' , 'content' , 'date']) # 去重 df.drop_duplicates(subset=['actor' , 'actor_url' , 'render' , 'render_url' , 'content' , 'date'],inplace = True) with pd.ExcelWriter(r'../data/npl_asan/comments.xlsx') as writer: df.to_excel(writer,index=False,sheet_name = 'Sheet1')
本篇到此結束,下篇再做資料處理。
不足:沒有使用代理,也沒有使用cookies池,需要注意sleep,不知道達到什麼情況會被封號;
Wall time: 1h 34min 57s,最終534條博文+6626條子評論,耗時也不少。有多機子可以考慮使用分散式爬蟲。