80851


**やりたいこと**  
自身が書いたスクレイピングコードをプログラム経験なしの知り合いに環境構築なしで共有するため、  
JupyterLabで書いたコードをGoogle Colabで実行しようとしました。  
しかし、どうにもGoogle Colabではエラーが出て動きません。

**実際のコード**  
JupyterLabでは全く問題ありませんでした。

[code]

    !pip install selenium
    !pip install webdriver_manager
    !pip install -U requests-html
    !pip install requests
    !pip install pandas
    from selenium import webdriver
    from selenium.common.exceptions import NoSuchElementException
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    from time import sleep
    from webdriver_manager.chrome import ChromeDriverManager
    import re
    import pandas as pd
    import datetime
    import requests
    
    op = Options()
    op.add_argument("--disable-gpu");
    op.add_argument("--disable-extensions");
    op.add_argument("--proxy-server='direct://'");
    op.add_argument("--proxy-bypass-list=*");
    op.add_argument("--start-maximized");
    op.add_argument("--headless");
    #browser = webdriver.Chrome(chrome_options=op)
    
    print('url取得')
    browser = webdriver.Chrome(ChromeDriverManager().install())
    url = 'https://www.mildom.com/ranking'
    #browser.get(url)
    data = []
    print('スクレイピング開始')
    def userID():
        try:
            for i in range(1, 98):
                browser.get(url)
                sleep(1.8)
                WebDriverWait(browser, 15).until(EC.presence_of_all_elements_located)
                namexpath = f'//*[@id="root"]/div/div/div[2]/div[2]/div/div[2]/div[1]/div[2]/div[1]/div[{i}]/a/div[4]'
                elem_username = browser.find_element_by_xpath(namexpath)
                username = elem_username.text
                #print(username)
                IDxpath = f'//*[@id="root"]/div/div/div[2]/div[2]/div/div[2]/div[1]/div[2]/div[1]/div[{i}]/a'
                elem_userURL = browser.find_element_by_xpath(IDxpath).get_attribute('href')
                ID = elem_userURL[-8:] #ID抽出
                #print(ID) #ID表示
    
                urlbefore = 'https://www.mildom.com/profile/'
                proURL = urlbefore + ID #profileのURL
                #print(proURL)
                
                #twitter垢取得
                browser.get(proURL)
                sleep(0.7)
                WebDriverWait(browser, 15).until(EC.presence_of_all_elements_located)
     
                Turlxpath = '//*[@id="root"]/div/div/div[2]/div[2]/div/div[2]/div[1]/div[2]/div[6]/div[2]/a'
                  #TwitterURL取得
                try:    
                    elem_TURL = browser.find_element_by_xpath(Turlxpath)
                    TwitterURL = elem_TURL.get_attribute("href")
                    #print(TwitterURL)
                except NoSuchElementException:
                    TwitterURL = 'null'
                    #print(TwitterURL)
                
    
                details = {}
                detum = details
                detum['配信者'] = username
                detum['mildomURL'] = proURL
                detum['TwitterURL'] = TwitterURL
                
                data.append(detum)
                
                #残り取得数          
                if i % 10 == 0:
                    print('現在取得数:' + str(i) + ' ' + '残り:' + str(97-i))
                                
        except:
            pass
            
                
        
        print(data)
        print(len(data))
        print('データリスト化・・・')
        print('csvファイル作成中')
        df = pd.DataFrame(data) 
        csv_name = datetime.datetime.today().strftime("%Y%m%d%H%M")
        csv = df.to_csv(csv_name + '.csv')
        csv
        print('Scraping終了')
            
                    
    userID()
    
    browser.quit()
    
[/code]

**Google Colabでのエラー内容**

[code]

    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-5-2979c7c78e85> in <module>()
         21 
         22 print('url取得')
    ---> 23 browser = webdriver.Chrome(ChromeDriverManager().install())
         24 url = 'https://www.mildom.com/ranking'
         25 #browser.get(url)
    
    2 frames
    /usr/local/lib/python3.7/dist-packages/webdriver_manager/utils.py in chrome_version(browser_type)
        153 
        154     if not version:
    --> 155         raise ValueError(f'Could not get version for Chrome with this command: {cmd}')
        156     current_version = version.group(0)
        157     return current_version
    
    ValueError: Could not get version for Chrome with this command: google-chrome --version || google-chrome-stable --version
    
[/code]

**試したこと**  
まずインストールし忘れているライブラリを確認しました。  
また、コードの基本的なエラーがないか、一度確かめなおしました。  
エラーメッセージ内にChromeのバージョンが取得できないと書かれているため、  
そちらについても確認しましたが、  
今回私はChromeDriverManagerを使って自動適したでchromedriverのバージョンを  
インストールするようにしているので問題はないのでは？といった具合です。

Google Colabでは実行できないのでしょうか？  
もし解決方法があれば教えてください。

**余談**  
非エンジニアの方々に、このようなプログラムを共有して、業務を効率化しようと考えているのですが、なるべく開発環境をさせずに共有したいと考えています。  
もし、Google ColabのほかにそのようなOS関係なく実行できる実行環境やまたはノウハウや技術を知っていれば教えていただけると幸いです。

**追加質問**  
期間が空きましたが、追加で質問失礼します。余談で教えていただいたTwitterURL取得について再度振り返ったところTwitterでのURLの取得方法がいまいちわかりません。ユーザープロフィールに関するURLである、https://cloudac-
cf-
jp.mildom.com/nonolive/gappserv/user/profileV2?user_id={user_id}&__platform=web
にアクセスしたところ次のように表示されました。  
コードを見ると、おそらくここからtwitterのURL情報を取得したようにも見えるのですが、どのようにしてURL情報を取得しているのでしょうか？  
[![画像の説明をここに入力](https://i.stack.imgur.com/1Cynm.png)](https://i.stack.imgur.com/1Cynm.png)


CC BY-SA 4.0
2021-08-16T13:46:34.280
80847
2021-09-12T14:08:41.940
2021-09-12T14:08:41.940
47546
47546
question
python3 web-scraping google-colaboratory
JupyterLabで問題なく実行されたコードがGoogle Colabで動かない


Google Colaboratory 環境に Google Chrome がインストールされていない事が原因でしょう。調べてみると、Chromium 用の
web driver をインストールして Selenium を利用する方法が一般的な様です。

参考までに、以下では Google Colaboratory 環境に Google Chrome/ChromeDriver
をインストールする場合について説明します。

  * Google Chrome をインストール

Google Chrome の APT repository を登録して認証キーを追加します。

  * 必要な Python パッケージをインストール

  * TCMalloc(Google 独自の C/C++ 用 memory allocator)による memory check を外す

どうやら Google Chrome は内部で memory leak を起こしているらしく、TCMalloc
が有効になっているとエラーチェックで異常終了してしまいます。なので、ChromeDriver
をインストールする直前に無効にしておきます。ChromeDriver をインストール後に元に戻します。

  * ChromeDriver をインストール

Google Chrome の実行オプションに `--no-sandbox` を追加します。

[code]

    # Install Google Chrome stable version
    !echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' >> /etc/apt/sources.list.d/google-chrome.list
    !wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
    !apt update
    !apt install google-chrome-stable
    
    # Install Python packages
    !pip install selenium
    !pip install webdriver_manager
    !pip install -U requests-html
    !pip install requests
    !pip install pandas
    
    # Import packages
    from selenium import webdriver
    from selenium.common.exceptions import NoSuchElementException
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    from time import sleep
    from webdriver_manager.chrome import ChromeDriverManager
    import re
    import pandas as pd
    import datetime
    import requests
    
    # Set up Chrome options
    op = Options()
    op.add_argument("--disable-gpu");
    op.add_argument("--disable-extensions");
    op.add_argument("--proxy-server='direct://'");
    op.add_argument("--proxy-bypass-list=*");
    op.add_argument("--start-maximized");
    op.add_argument('--no-sandbox')  # without sandbox
    op.add_argument("--headless");
    
    # Disable memory allocation checker
    import os
    if 'LD_PRELOAD' in os.environ:
      ld_preload = os.environ['LD_PRELOAD']
      del os.environ['LD_PRELOAD']
    
    # Install Chrome driver
    browser = webdriver.Chrome(ChromeDriverManager().install(), options=op)
    
    # Enable memory allocation checker
    if 'ld_preload' in locals():
      os.environ['LD_PRELOAD'] = ld_preload
    
[/code]

以上を実行後に `url = 'https://www.mildom.com/ranking'` 以降のコードを実行してみたところ、正常終了しました(CSV
ファイルが作成されました)。

**追記**

`userID()` 関数を `df`(dataframe) を返す様に変更して、Colaboratory
でデータフレームを表示するとスクレイピングした内容を確認しやすくなるかと思います。

[code]

    def userID():
         :
    
        print('Scraping終了')
        return df
    
    df = userID()
    browser.quit()
    
[/code]

[![dataframe](https://i.stack.imgur.com/cP0Xu.png)](https://i.stack.imgur.com/cP0Xu.png)


CC BY-SA 4.0
2021-08-16T16:31:49.453
80851
2021-08-16T19:18:16.263
2021-08-16T19:18:16.263
47127
47127
80847
answer


> **余談**  
>
> 非エンジニアの方々に、このようなプログラムを共有して、業務を効率化しようと考えているのですが、なるべく開発環境をさせずに共有したいと考えています。もし、Google
> ColabのほかにそのようなOS関係なく実行できる実行環境やまたはノウハウや技術を知っていれば教えていただけると幸いです。

今回のスクレイピングに関してですが、Selenium を利用しなくても可能です。参考までに解説しておきます。

Mildom にアクセスする際にウェブブラウザで通信状況を確認してみると、ランキングとユーザープロフィールのデータを別の URL から取得しています。

  * ランキングデータ  
`https://cloudac-cf-jp.mildom.com/nonolive/gappserv/rank/locationGiftRankV2`

  * ユーザプロフィール  
`https://cloudac-cf-jp.mildom.com/nonolive/gappserv/user/profileV2`

これらの URL に対して HTTP GET を行うと(適宜 query string を付加します)、HTTP response として JSON
形式のデータが返ってきます。このデータを加工して CSV ファイルに保存します。

[code]

    from datetime import datetime as dt
    import pandas as pd
    import requests
    
    # ranking URL
    url_rank = (
      'https://cloudac-cf-jp.mildom.com/nonolive/gappserv/rank/locationGiftRankV2' +
      '?term=this&type=hour&rank_type=receive')
    
    # user profile URL
    url_user_profile = (
      'https://cloudac-cf-jp.mildom.com/nonolive/gappserv/user/profileV2' +
      '?user_id={user_id}&__platform=web')
    
    # scraping
    headers = {'Content-Type': 'application/json'}
    r = requests.get(url_rank, headers=headers)
    users = pd.DataFrame.from_dict(r.json()['body']['models'])
    users = users[['loginname', 'user_id']]
    
    # twitter URL
    twitter_url_prefix = 'https://twitter.com/'
    twitter_url = []
    for id in users.user_id:
      user_info = (
        requests
          .get(url_user_profile.format(user_id=id), headers=headers)
          .json()['body']['user_info'])
      url = ''
      if 'sns_ids' in user_info and 'twitter' in user_info['sns_ids']:
        url = user_info['sns_ids']['twitter'].strip()
      twitter_url.append((twitter_url_prefix + url) if url else '')
    
    users['TwitterURL'] = twitter_url
    
    # mildom profile URL
    users['user_id'] = (
      'https://www.mildom.com/profile/' + users['user_id'].astype(str))
    
    # rename columns
    users.rename(
      columns={'loginname': '配信者', 'user_id': 'mildomURL'},
      inplace=True)
    
    # save with CSV
    csv_name = dt.today().strftime('%Y%m%d%H%M') + '.csv'
    users.to_csv(csv_name)
    
[/code]

[![user
ranking](https://i.stack.imgur.com/ELLcG.png)](https://i.stack.imgur.com/ELLcG.png)

#### 追記

> そのwebブラウザの通信状況の確認というのがわかりません。今回もソースコードから確認できたのでしょうか？

こちらでは FireFox の開発者ツールを利用していますが、`Ctrl`+`Shift`+`e` でネットワークタブが開きます。

[![FireFox network
tab](https://i.stack.imgur.com/Spg8c.png)](https://i.stack.imgur.com/Spg8c.png)

今回も `XMLHttpRequest(XHR)` を調べていました。上記画像でメニュバーにある `XHR`
がグレー化していることが判るかと思います(`XHR` のみを選択)。そして、右側のペインに HTTP response が表示されていますが、中身は
JSON データで `Object` が 100 個あるので、これがランキングデータを取得している URL だろうと判断したわけです。HTTP GET の
query string は右側ペインのメニューにある `Headers` をクリックすると表示されます。

> また、通信状況を自身で調べられるようになるにはどのようなことを学ぶ必要があるでしょうか？

`HTTP GET/POST`, `HTTP requst/responce`, `XMLHttpRequest(XHR)`
辺りがキーワードになるかと思いますが、この様な可視化ツールを使いながら、理解できないことがあれば調べつつ慣れていくとよろしいかと。


CC BY-SA 4.0
2021-08-17T05:58:23.740
80863
2021-08-17T08:26:46.270
2021-08-17T08:26:46.270
47127
47127
80847
answer