# 使用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()`分頁。