使用selenium自动化工具爬取微博内容和评论
任務需求是爬取微博的內容和評論。一開始我是準備直接用正常的爬蟲來做,但是發現微博上的內容幾乎都是動態加載生成的。所以了解了一下就學習使用·selenium自動化測試工具來爬取相關數據。
首先是不登錄微博,發現只能查看最多二十條數據,這自然限制太大所以還是需要實現登錄后再爬取。
1.登錄微博
由于微博現在的登錄不能只輸入賬號密碼,所以通過查找了一些方法后選用了注入cookie來實現自動登錄。而想要注入的cookie需要自己先登錄獲得。這里直接使用了各位大佬給出的方法。實現掃碼登錄后獲取cookie。
from selenium import webdriver from time import sleep import json from selenium.webdriver.common.by import Byif __name__ == '__main__':driver = webdriver.Chrome()driver.maximize_window()driver.get('https://weibo.com/login.php')sleep(6)a = driver.find_element(By.XPATH, '//*[@id="pl_login_form"]/div/div[1]/div/a[2]')a.click()sleep(10)dictCookies = driver.get_cookies() # 獲取list的cookiesjsonCookies = json.dumps(dictCookies) # 轉換成字符串保存with open('微博_cookies.txt', 'w') as f:f.write(jsonCookies)print('cookies保存成功!')2.通過獲取到的cookie實現自動登錄然后爬取用戶微博內容和評論
2.1打開瀏覽器,進入到登錄頁面。這里我最大化窗口了。
# 打開瀏覽器,進入到微博登錄頁面 def browser_initial():browser = webdriver.Chrome()browser.maximize_window()browser.get('https://weibo.com/login.php')return browser2.2實現自動化登錄
# 將已經登錄獲得的cookie寫入,實現自動登錄 def log_csdn(browser):with open('微博_cookies.txt', 'r', encoding='utf8') as f:listCookies = json.loads(f.read())# 往browser里添加cookiesfor cookie in listCookies:cookie_dict = {'domain': '.weibo.com','name': cookie.get('name'),'value': cookie.get('value'),"expires": '','path': '/','httpOnly': False,'HostOnly': False,'Secure': False}#print(cookie_dict)browser.add_cookie(cookie_dict)sleep(1)browser.get('https://weibo.com/login.php')登錄后的頁面如下圖
?
2.3搜索內容并且爬取
這時候需要在左上角的搜索框輸入自己需要搜索的用戶,然后通過按回車來實現搜索
?得到新的頁面里可以看到最上方會顯示相關的賬戶,找到相關元素并點擊即可
最后進入到用戶的完整頁面
這時侯就可以開始爬取用戶的微博信息和評論了。由于微博的內容是動態加載的,通過F12可以看到一開始是僅展示六條內容的元素
通過滑動,元素會逐漸增加,但是上限是12個,并且后面會出現元素順序和微博內容順序不符的情況。如果單單爬取微博的內容,不爬評論那還好,只需要定位到每一個元素塊,獲取其內部的text文本然后處理一下就可以獲得自己想要的信息。但是由于還要爬取相應的評論內容,并且評論還要和微博內容相對應,所以不能直接進行爬取。
這里我選擇微博內容里的時間元素里的href
?
?通過點擊這個a標簽,可以跳轉到該條微博的詳情頁面
這時候就可以分塊爬起微博的內容以及轉發數、評論數、點贊數和評論的內容了。要注意的是這里的轉發數評論數這些可能存在多個,比如此圖里是轉發他人微博,他人微博里也有轉發數這些。還有就是評論的內容有可能是開啟精選后的,和普通的評論內容要做判斷。?爬取完微博內容和評論后點擊上方的返回按鈕,回到之前的頁面。
hrefs = []# 搜索內容 def search(username):# 等待元素出現再進行下一步WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "woo-pop-ctrl")))# 獲取搜索框元素searchinput = browser.find_element(By.CLASS_NAME, 'woo-input-main')# 將要搜索的內容寫入搜索框searchinput.send_keys(username)# 等待0.5秒后按回車sleep(0.2)searchinput.send_keys(Keys.ENTER)# 轉移句柄到新的頁面new_window = browser.window_handles[-1]# 關閉原來的頁面browser.close()# 窗口轉移到新的頁面browser.switch_to.window(new_window)# 等待WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "card-wrap")))# 定位用戶微博頭像并點擊weibo = browser.find_element(By.XPATH, '//div[@class="card card-user-b s-brt1 card-user-b-padding"]/div/a')weibo.click()new_window = browser.window_handles[-1]browser.switch_to.window(new_window)WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "vue-recycle-scroller__item-view")))# 微博一次最多給12條內容的元素,并且給出的元素不保證順序。# 所以第一次進入頁面的時候獲取所有的內容元素,a標簽里的href唯一,所以將其提取出來for t in range(3):a = browser.find_elements(By.XPATH, '//div[@class="woo-box-item-flex head_main_3DRDm"]/div/div[2]/a')# 在獲取到的列表里進行篩選,已經爬取過的微博就跳過for i in range(len(a)):if a[i].get_attribute("href") in hrefs:print("已經搜索過")continueelse:print("還沒搜索過")# 每次都向下滑動400像素,大致符合一條微博的高度changepage(400)# sleep(0.5)newpage = a[i].get_attribute("href")# 打印hrefprint(newpage)hrefs.append(newpage)# print(comments)# 打印已經搜索的微博內容數print(len(hrefs))# 使用js腳本來點擊元素,否則可能出現元素不在網頁上,無法交互的報錯# a[i].click()browser.execute_script("arguments[0].click();", a[i])# 不要直接用href去請求,否則點擊返回的時候會直接回到微博首頁面# browser.get(newpage)sleep(0.5)# 爬取具體內容頁面的內容和評論findall()sleep(0.2)# 找到返回按鈕并點擊WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.XPATH,'//div[@class="woo-box-flex woo-box-alignCenter Bar_left_2J3kl Bar_hand_2VAG1"]/i')))back = browser.find_element(By.XPATH,'//div[@class="woo-box-flex woo-box-alignCenter Bar_left_2J3kl Bar_hand_2VAG1"]/i')back.click()?
text = []# 將頁面向下滑動px像素 def changepage(px):browser.execute_script("window.scrollBy(0, {})".format(px))# 爬取微博的內容和評論 def findall():# 等待頁面元素加載WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "Feed_body_3R0rO")))body = browser.find_element(By.CLASS_NAME, 'Feed_body_3R0rO')# 通過換行來劃分內容bodytext = body.text.split("\n")print(bodytext)# 找到轉發評論點贊的元素,但是如果有微博內容為轉發他人的微博,則存在兩個footer元素,# 所以尋找多個,然后取最后那一個footer = browser.find_elements(By.TAG_NAME, 'footer')footertext = footer[-1].text.split("\n")print(footertext[1])WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "Detail_box_3Jeom")))try:prompt = browser.find_element(By.CLASS_NAME, "RepostCommentList_tip_2O5W-")print(prompt.text)t = Falseexcept:t = Trueprint(t)while t:try:browser.find_element(By.XPATH, '//div[@class="Bottom_text_1kFLe"]')t = Falseexcept:t = TrueWebDriverWait(browser, 15).until(EC.presence_of_element_located((By.XPATH, '//div[@class="vue-recycle-scroller__item-wrapper"]')))pagecomment = browser.find_elements(By.XPATH, '//div[@class="vue-recycle-scroller__item-view"]')for i in pagecomment:comment = i.text.split("\n")if comment in text:continueelse:print(comment)text.append(comment)sleep(0.1)changepage(600)?最后爬取內容和評論的總的代碼如下:
from selenium import webdriver from time import sleep import json from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keystext = [] hrefs = []# 打開瀏覽器,進入到微博登錄頁面 def browser_initial():browser = webdriver.Chrome()browser.maximize_window()browser.get('https://weibo.com/login.php')return browser# 將已經登錄獲得的cookie寫入,實現自動登錄 def log_csdn(browser):with open('微博_cookies.txt', 'r', encoding='utf8') as f:listCookies = json.loads(f.read())# 往browser里添加cookiesfor cookie in listCookies:cookie_dict = {'domain': '.weibo.com','name': cookie.get('name'),'value': cookie.get('value'),"expires": '','path': '/','httpOnly': False,'HostOnly': False,'Secure': False}#print(cookie_dict)browser.add_cookie(cookie_dict)sleep(1)browser.get('https://weibo.com/login.php')#print(browser.get_cookies())#browser.refresh() # 刷新網頁,cookies才成功# 搜索內容 def search(username):# 等待元素出現再進行下一步WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "woo-pop-ctrl")))# 獲取搜索框元素searchinput = browser.find_element(By.CLASS_NAME, 'woo-input-main')# 將要搜索的內容寫入搜索框searchinput.send_keys(username)# 等待0.5秒后按回車sleep(0.2)searchinput.send_keys(Keys.ENTER)# 轉移句柄到新的頁面new_window = browser.window_handles[-1]# 關閉原來的頁面browser.close()# 窗口轉移到新的頁面browser.switch_to.window(new_window)# 等待WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "card-wrap")))# 定位用戶微博頭像并點擊weibo = browser.find_element(By.XPATH, '//div[@class="card card-user-b s-brt1 card-user-b-padding"]/div/a')weibo.click()new_window = browser.window_handles[-1]browser.switch_to.window(new_window)WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "vue-recycle-scroller__item-view")))# 微博一次最多給12條內容的元素,并且給出的元素不保證順序。# 所以第一次進入頁面的時候獲取所有的內容元素,a標簽里的href唯一,所以將其提取出來for t in range(3):a = browser.find_elements(By.XPATH, '//div[@class="woo-box-item-flex head_main_3DRDm"]/div/div[2]/a')# 在獲取到的列表里進行篩選,已經爬取過的微博就跳過for i in range(len(a)):if a[i].get_attribute("href") in hrefs:print("已經搜索過")continueelse:print("還沒搜索過")# 每次都向下滑動400像素,大致符合一條微博的高度changepage(400)# sleep(0.5)newpage = a[i].get_attribute("href")# 打印hrefprint(newpage)hrefs.append(newpage)# print(comments)# 打印已經搜索的微博內容數print(len(hrefs))# 使用js腳本來點擊元素,否則可能出現元素不在網頁上,無法交互的報錯# a[i].click()browser.execute_script("arguments[0].click();", a[i])# 不要直接用href去請求,否則點擊返回的時候會直接回到微博首頁面# browser.get(newpage)sleep(0.5)# 爬取具體內容頁面的內容和評論findall()sleep(0.2)# 找到返回按鈕并點擊WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.XPATH,'//div[@class="woo-box-flex woo-box-alignCenter Bar_left_2J3kl Bar_hand_2VAG1"]/i')))back = browser.find_element(By.XPATH,'//div[@class="woo-box-flex woo-box-alignCenter Bar_left_2J3kl Bar_hand_2VAG1"]/i')back.click()# 將頁面向下滑動px像素 def changepage(px):browser.execute_script("window.scrollBy(0, {})".format(px))# 爬取微博的內容和評論 def findall():# 等待頁面元素加載WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "Feed_body_3R0rO")))body = browser.find_element(By.CLASS_NAME, 'Feed_body_3R0rO')# 通過換行來劃分內容bodytext = body.text.split("\n")print(bodytext)# 找到轉發評論點贊的元素,但是如果有微博內容為轉發他人的微博,則存在兩個footer元素,# 所以尋找多個,然后取最后那一個footer = browser.find_elements(By.TAG_NAME, 'footer')footertext = footer[-1].text.split("\n")print(footertext[1])WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, "Detail_box_3Jeom")))try:prompt = browser.find_element(By.CLASS_NAME, "RepostCommentList_tip_2O5W-")print(prompt.text)t = Falseexcept:t = Trueprint(t)while t:try:browser.find_element(By.XPATH, '//div[@class="Bottom_text_1kFLe"]')t = Falseexcept:t = TrueWebDriverWait(browser, 15).until(EC.presence_of_element_located((By.XPATH, '//div[@class="vue-recycle-scroller__item-wrapper"]')))pagecomment = browser.find_elements(By.XPATH, '//div[@class="vue-recycle-scroller__item-view"]')for i in pagecomment:comment = i.text.split("\n")if comment in text:continueelse:print(comment)text.append(comment)sleep(0.1)changepage(600)if __name__ == "__main__":# 打開瀏覽器進入微博登錄頁面browser = browser_initial()# 使用cookie登錄微博log_csdn(browser)# 爬取相關用戶的評論search("杭州地鐵")里面的數據處理還沒做,大家可以自己打印出來后根據自己的需要進行處理。
總結
以上是生活随笔為你收集整理的使用selenium自动化工具爬取微博内容和评论的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AngularJS-模块化
- 下一篇: 基于Tesseract的OCR识别--身