# 使用Selenium來自動操作Google搜尋並爬回搜尋結果 ## 前言 因為要在Google搜尋上爬回結果會需要有一些動作: 1. 輸入要搜尋的關鍵字 2. 點擊Enter 3. 取得搜尋結果並解析 因此無法直接以BeautifulSoup來爬取內容,因為在搜尋結果出現之前,是不會有搜尋結果的,因此借助Selenium的互動方法來模擬人的文字輸入和點擊Enter,然後爬回內容後再交給BeautifulSoup來解析搜尋結果。 ## 資料定位的三種方式 Google搜尋頁雖然看起來很簡約,但其背後的網頁語法卻十分複雜,想要定位出需要的搜尋框或是搜尋結果有下列三種方式: 土法煉鋼:在瀏覽器點右鍵,檢視原始碼後直接用網頁內容來搜尋資料被什麼元素包住。 先排版:有些網站原始碼較混亂,可以使用網路上的HTML排版工具先排版後再進行資料定位。 使用Chrome的開發工具,在想要定位的元素上點滑鼠右鍵->檢查(Inspect) ## 完整程式碼 ```python= from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.keys import Keys from bs4 import BeautifulSoup import requests driver = webdriver.Chrome() driver.implicitly_wait(10) driver.get('https://www.google.com/') print(driver.title) html = driver.page_source try: search = driver.find_element(By.NAME, 'q') print(search.tag_name) search.send_keys('aaron') search.send_keys(Keys.ENTER) items = driver.find_elements(By.CLASS_NAME, "LC20lb") addrs = driver.find_elements(By.CLASS_NAME, "yuRUbf") all = zip(items, addrs) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} - {addr}') except NoSuchElementException: print('無法定位') driver.quit() ``` **說明:** 1. 透過Chrome的開發工具,可以找到Google搜尋框的input有個name屬性,值為q,因此使用name屬性來定位。 2. 透過`send_key()`函式來輸出搜尋文字,再送出Enter按鍵。 3. 透過Chrome的開發工具,會發現搜尋結果的標題都會有`LC20lb`這個class,且搜尋結果的超連結都會被div標籤,且該標籤都有`yuRUbf`class名稱 4. 在取得所有包圍超連結的div標籤後,再次呼叫`find_element()`函式來取得裡面的第一個a標籤href屬性值就可以得到超連結。 ## 進階練習 #### 爬出搜尋結果前五個分頁與相關搜尋文字 ```python= from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.keys import Keys import time driver = webdriver.Chrome('./chromedriver') driver.implicitly_wait(10) driver.get('https://www.google.com') # 連線到Google搜尋網站 print(driver.title) try: # 定位搜尋輸入框 search_input = driver.find_element(By.NAME, 'q') # 送出搜尋文字 search_input.send_keys('aaron') time.sleep(1) # 送出ENTER按鍵 search_input.send_keys(Keys.ENTER) time.sleep(1) # driver內容就是當前的頁面,不管網頁跳到哪裡去 # 相關搜尋 print('相關搜尋:') related = driver.find_elements(By.CLASS_NAME, 's75CSd') # 相關搜尋 for re in related: print(re.find_element(By.TAG_NAME, 'b').text) # 解析搜尋結果 subjects = driver.find_elements(By.CLASS_NAME, 'LC20lb') # 搜尋結果標題 links = driver.find_elements(By.CLASS_NAME, 'yuRUbf') # 搜尋結果連結 all = zip(subjects, links) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} [{addr}]') # 練習: 將搜尋結果的前五頁都爬出來 for page_num in range(2, 6): print('Page', page_num) # 定位每一頁的分頁超連結 page = driver.find_element(By.CSS_SELECTOR, 'a[aria-label="Page ' + str(page_num) + '"]') # 點擊分頁超連結 page.click() # 解析搜尋結果 subjects = driver.find_elements(By.CLASS_NAME, 'LC20lb') # 搜尋結果標題 links = driver.find_elements(By.CLASS_NAME, 'yuRUbf') # 搜尋結果連結 # 相關搜尋 print('相關搜尋:') related = driver.find_elements(By.CLASS_NAME, 's75CSd') # 相關搜尋 for re in related: print(re.find_element(By.TAG_NAME, 'b').text) all = zip(subjects, links) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} [{addr}]') # time.sleep(1) except NoSuchElementException: print('定位失敗') driver.quit() ``` > **注意:** > > 如果要爬取搜尋結果每個分頁,需注意當爬蟲進入下一個分頁的時候,上的分頁的網址會失效,需要重新取得分頁網址,而非一次幸存下所有分頁網址。 > > 或是可以使用`click()`方法進入下一個分頁,而非重新`webdriver.get()`分頁。