[Pythonスクレイピング] Beautifulsoup & selenium を使ってgoogle検索top10見てみた



# はじめに
以前seoライティングのお仕事をしていた際に、検索ワードのtop10のurl、タイトルを手作業で集める作業を行っていました。
その際に、スクレイピングを使用することで作業を大幅に省略できたのでその方法を記します。

自らブログを書いて稼ぎたいと思っている方に、どのようなタイトルにするとアクセスされやすいのか、またexcelよりurlに飛べるようになるのでライティングの作業を大幅に削減することが出来ます。

# 目次
#### 流れ

#### コードの全貌

#### 解説
**1.googleを立ち上げる**
- webdriver.Chrome()
- driver.get("検索したいurl")

**2.検索ボックスより検索したいワードを入力しenterする**
- driver.find_element_by_name()
- .send_keys("入れたいワード")
- .submit()
- time.sleep(秒数)

**3.検索結果よりurlを獲得する**
- driver.page_source.encode('utf-8')
- BeautifulSoup(html,"html.parser")
- soup.select()

**4.それぞれのurlにアクセスしtitle属性とdescription属性を取得する**
- driver.back()

**5.まとめたデータをexcelファイルで書き出す**
- driver.quit()

#### ソースコード


# 流れ

1.googleを立ち上げる
2.検索ボックスより検索したいワードを入力しenterする
3.検索結果よりurlを獲得する
4.それぞれのurlにアクセスしtitle属性とdescription属性を取得する
5.まとめたデータをexcelファイルで書き出す



# コード全貌

```
import time                                 # スリープを使うために必要
from selenium import webdriver              # Webブラウザを自動操作する（python -m pip install selenium)
from selenium.webdriver.common.keys import Keys
import chromedriver_binary
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np                               
#好みでここは変更する
from selenium.webdriver.chrome.options import Options

class Chrome_search:
    def __init__(self):
        self.url = "https://www.google.co.jp/search"
        self.search_word = input("検索ワードを入れてください:")
        self.search_num = int(input("何件取得しますか："))#何件の取得をするか
        
        self.options = Options()
        #self.options.add_argument('--headless') ##ブラウザを立ち上げなくなる
        #self.options.add_argument('--no-sandbox')　 ##アクセスの制限は消えるがどんなプログラムでもダウンロードするので危険
        self.options.add_argument('--disable-dev-shm-usage')#メモリを一杯に使えるからchromeがフラッシュバックしないとか　
        
    def search(self):
        driver = webdriver.Chrome(options=self.options) # mac方はこの行をコメントアウト
        driver.get(self.url)
        search = driver.find_element_by_name('q')  # HTML内で検索ボックス(name='q')を指定する
        search.send_keys(self.search_word)        # 検索ワードを送信する
        search.submit()                         # 検索を実行
        time.sleep(1)    
        #格納ボックスを作成                                                 
        title_list = []     #titleを格納
        url_list = []     #urlを格納
        description_list = []   #meta-descriptionを格納
        ##html取得        
        html = driver.page_source.encode('utf-8') 
        soup = BeautifulSoup(html, "html.parser")        
        # 検索結果のタイトルとリンクを取得
        link_elem01 = soup.select('.yuRUbf > a')
        # リンクのみを取得し、余分な部分を削除する
        if self.search_num<=len(link_elem01):       #urlの数が検索数以下だったらurlの分だけ解析
            for i in range(self.search_num):
                url_text = link_elem01[i].get('href').replace('/url?q=', '')
                url_list.append(url_text)  
        elif self.search_num > len(link_elem01):
            for i in range(len(link_elem01)):
                url_text = link_elem01[i].get('href').replace('/url?q=','')
                url_list.append(url_text)
        
        time.sleep(1)
        
        #この段階でurlの作成は完了
        #url_listから次々とんでtitleを取得する
        for i in range(len(url_list)):
            driver.get(url_list[i])
            ##html取得 
            html2 = driver.page_source.encode('utf-8') 
            ##BeautifulSoup用にパース 
            soup2 = BeautifulSoup(html2, "html.parser")
            #titleの取得
            title_list.append(driver.title)
            # Descriptionの取得
            try:
                description = driver.find_element_by_xpath(("//meta[@name='description']")).get_attribute("content")
                description_list.append(description)
            except:
                description_list.append("")
            #ブラウザを一旦戻す
            driver.back()
            time.sleep(0.3)
        #ここで一回保存できているか展開   
        print(url_list)
        print(title_list)
        print(description_list)

        search_ranking = np.arange(1,len(url_list)+1)
        
        my_list = {"url": url_list,"ranking":search_ranking, "title": title_list,"description":description_list}
        my_file = pd.DataFrame(my_list)
        driver.quit()
        my_file.to_excel(self.search_word+".xlsx",self.search_word,startcol=2,startrow=1)
        df = pd.read_excel(self.search_word+".xlsx")
        return df
    
    
if __name__ == '__main__':
    se = Chrome_search()
    df=se.search()
    df.head()
```

# 解説

コードの解説をしていきます。

## ライブラリの読み込み

```
import time                                 # スリープを使うために必要
from selenium import webdriver              # Webブラウザを自動操作する（python -m pip install selenium)
from selenium.webdriver.common.keys import Keys
import chromedriver_binary
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np  
#好みでここは変更する
from selenium.webdriver.chrome.options import Options
```

肝となるライブラリの説明は以下のとおりです。

time : 時間制御をするライブラリ
selenium : ブラウザを制御するライブラリ
beautifulsoup  : スクレイピングをするライブラリ
chromedriver_binary : seleniumのブラウザをgoogle chromeにする

## 1.Googleを立ち上げる

googleでブラウザを立ち上げるのは以下の箇所です。

```
driver = webdriver.Chrome(options=self.options) # mac方はこの行をコメントアウト
driver.get(self.url)
```


`driver = webdriver.Chrome(options=self.options)`
はseleniumを立ち上げるための宣言です。

`driver.get("検索したいurl")`
でchromeで検索したいurlにアクセスすることができます。

今回は`self.url=googleのブラウザ`としています。

## 2.検索ボックスより検索したいワードを入力しenterする

seleniumを使ってgoogle検索フォームより検索をするコードは以下の箇所です。

```
search = driver.find_element_by_name('q')  # HTML内で検索ボックス(name='q')を指定する
search.send_keys(self.search_word)        # 検索ワードを送信する
search.submit()                         # 検索を実行
time.sleep(1)                          #1秒停止する
```

`driver.find_element_by_name()`でname属性を持つelementヲ抜き出すことが出来ます。
find_element_by_のあとには,classやid等も指定することが出来ます。
`.send_keys("入れたいワード") `でdriver.fine...で指定した要素にいれたいワードを入力することが出来ます。
`submit()`がenterの役割をします。
`time.sleep(秒数)`で実行を指定した秒数だけ止めることが出来ます。ブラウザの読み込み時に使用することで画面表示まで待つことが出来、通信によるラグのエラーが出にくくなります。


## 3.検索結果よりurlを獲得する
2で実際に画面転移し検索結果が表示されます。

検索結果からurlを取得するコードは以下の箇所です。

```
#格納ボックスを作成                                                 
title_list = []     #titleを格納
url_list = []     #urlを格納
description_list = []   #meta-descriptionを格納
##html取得        
html = driver.page_source.encode('utf-8') 
soup = BeautifulSoup(html, "html.parser")        
# 検索結果のタイトルとリンクを取得
link_elem01 = soup.select('.yuRUbf > a')
# リンクのみを取得し、余分な部分を削除する
if self.search_num<=len(link_elem01):       #urlの数が検索数以下だったらurlの分だけ解析
    for i in range(self.search_num):
        url_text = link_elem01[i].get('href').replace('/url?q=', '')
        url_list.append(url_text)  
elif self.search_num > len(link_elem01):
    for i in range(len(link_elem01)):
        url_text = link_elem01[i].get('href').replace('/url?q=','')
        url_list.append(url_text)

time.sleep(1)

```

このコードで特に重要なのは以下の箇所です。


```
##html取得        
html = driver.page_source.encode('utf-8') 
soup = BeautifulSoup(html, "html.parser")        
# 検索結果のタイトルとリンクを取得
link_elem01 = soup.select('.yuRUbf > a')
```

`driver.page_source.encode('utf-8') `　で文字コードを強制的にutf-8にセットします。
`BeautifulSoup(html,"html.parser")`は宣言なので呪文のようなものだとして覚えておきましょう。
`soup.select()`でcssのselectorより指定の要素を取り出すことが出来ます。
その後のコードで`link_elem01[i].get('href')`としていますが、soup.selectで得たデータのhref属性を読み取っています。

## 4.titleとdescriptionを取得する

titleとdescriptionを取得するコードは以下の箇所です。

```
for i in range(len(url_list)):
    driver.get(url_list[i])
    ##html取得 
    html2 = driver.page_source.encode('utf-8') 
    ##BeautifulSoup用にパース 
    soup2 = BeautifulSoup(html2, "html.parser")
    #titleの取得
    title_list.append(driver.title)
    # Descriptionの取得
    try:
        description = driver.find_element_by_xpath(("//meta[@name='description']")).get_attribute("content")
        description_list.append(description)
    except:
        description_list.append("")
    #ブラウザを一旦戻す
    driver.back()
    time.sleep(0.3)
```

3で得られたurlのリストをもとにseleniumで検索をかけていきます。
いままで出たbeautifulsoupとseleniumの知識でコードが完成しています。
`driver.back()`はブラウザをバックするコマンドです。

## 5.まとめたデータをexcelファイルで書き出す
4まででurl,title,descriptionが入ったリストを作成しました。
最後にpandasを使ってデータを整形し、excelファイルに書き込む作業を行っていきます。
該当のコードは以下です。

```
my_list = {"url": url_list,"ranking":search_ranking, "title": title_list,"description":description_list}
my_file = pd.DataFrame(my_list)
driver.quit()
my_file.to_excel(self.search_word+".xlsx",self.search_word,startcol=2,startrow=1)
df = pd.read_excel(self.search_word+".xlsx")
```

pandasの操作については特に説明は不要でしょう。
`driver.quit()`で最後にブラウザのシャットダウンを行います。

# ソースコード
ソースコードは以下のgithubより取得することが出来ます。
ぜひ、ライティングに役立ててください。
https://github.com/marumaru1019/python_scraping/tree/master