実現したいこと
GCPのcloud functionsを用いてpythonスクリプトによるスクレイピング&メール送信を定期実行させたい
前提
M1チップのMacbook proを使用しています。
pythonにて作成したスクリプトを毎日定時に実行させるために当初はcronを用いて実現しようと考えておりましたがPCがスリープ状態であると実行できないため、クラウドサービス、特に今回はGCPの
Cloud Functionsによる定期実行を試みました。
しかしデプロイはできたもののテストするとchromeバイナリに関する下のエラーメッセージが返され正常にスクリプトを完了させることができません。
ローカル環境では問題なく実行できており、解決に至らなかったため解決方法をご教授いただければ幸いです。
(プログラミング初心者のためなるべく噛み砕いて記載いただけると助かります。)
発生している問題・エラーメッセージ
Message: unknown error: cannot find Chrome binary
該当のソースコード
Python
1#スクレイピング用ライブラリ 2from selenium import webdriver 3from selenium.webdriver.common.by import By 4import time 5from bs4 import BeautifulSoup 6from datetime import datetime, date, timedelta 7import configparser 8import sys 9from selenium.webdriver.chrome.options import Options 10from selenium.webdriver.chrome.service import Service 11 12#メール作成用ライブラリ 13import smtplib 14from email.mime.text import MIMEText 15from email.mime.multipart import MIMEMultipart 16from email.utils import formatdate 17 18#iniファイル用ライブラリ 19import os 20 21def hello_pubsub(event, context): 22 try: 23 #iniファイルの読み込み 24 config_ini = configparser.ConfigParser() 25 ini_dir = os.path.dirname(__file__) 26 ini_path = os.path.join(ini_dir, 'kulasis.ini') 27 config_ini.read(ini_path, encoding='utf-8') 28 29 #driverオブジェクトの作成 30 #パスの設定 31 driver_dir = os.path.dirname(__file__) 32 driver_path = os.path.join(driver_dir, 'chromedriver.exe') 33 options = Options() 34 options.add_argument("--headless") 35 options.add_argument("no-sandbox") 36 service = Service(driver_path) 37 driver = webdriver.Chrome(service=service, options=options)#ヘッドレスモードはここにoption追加 38 39 #お知らせを開く 40 info_url = 'https://www.k.kyoto-u.ac.jp/student/g/medh/global_notice/general' 41 driver.get(info_url) 42 time.sleep(3) 43 44 #ユーザーIDの入力 45 ID_xpath = '//*[@id="username"]' 46 ID = config_ini.get('Login', 'username') 47 driver.find_element(By.XPATH,ID_xpath).send_keys(ID) 48 49 #パスワードの入力 50 PASS_xpath = '//*[@id="password"]' 51 PASS = config_ini.get('Login', 'password') 52 driver.find_element(By.XPATH,PASS_xpath).send_keys(PASS) 53 54 #ログインボタンのクリック 55 loginbutton_xpath = '/html/body/div/div/div/form/div[4]/button' 56 driver.find_element(By.XPATH,loginbutton_xpath).click() 57 time.sleep(3) 58 59 #html要素を取得 60 html = driver.page_source 61 62 #htmlのパース 63 soup = BeautifulSoup(html,"html.parser") 64 65 #tbodyの取得 66 class_name = 'list' 67 elements = soup.find_all('tbody',{'class',class_name}) 68 69 #今日の日付の取得 70 today = date.today() 71 72 #要素の取得と本文の作成 73 #iniファイル内のuserセクションを取得 74 for section_name in config_ini.sections(): 75 if section_name.startswith('user'): 76 #各ユーザーの情報を取得 77 user_info = config_ini[section_name] #セクション名 78 address = user_info.get('address') #メールアドレス 79 department = user_info.get('department') #学部 80 81 #情報の有無識別のためのオブジェクト(デフォルトはFalse) 82 is_info_exist = False 83 84 #html形式でメール本文を作成する 85 #冒頭部分 86 body = '<body>' 87 body += '<p>KULASISにて過去3日以内に掲載された<br>お知らせがあります。</p>' 88 body += '<p><br></p>' 89 body += '所属:{}'.format(department) 90 91 #条件に合致する情報を取得 92 for tbody in elements: 93 trs = tbody.find_all('tr') 94 for tr in trs: 95 tds = tr.find_all('td') 96 td0 = tds[0].text.strip() #学部情報 97 td3 = tds[3].text.strip() #内容 98 td4 = tds[4].text.strip()[:10] #日付 99 if '(' in td4: 100 td4 = td4[:-1] 101 102 td4_date = datetime.strptime(td4,'%Y/%m/%d').date() 103 104 if td4_date >= today - timedelta(days=3) and td0 == department: #情報がある場合 105 #内容部分 106 body += '<p>■ {td3} <br>[掲載日]:{td4}</p>'.format(td3=td3, td4=td4) 107 #識別オブジェクトの更新 108 is_info_exist = True 109 110 #Chromeの終了 111 driver.quit() 112 113 #リンク部分 114 url = 'https://student.iimc.kyoto-u.ac.jp' 115 link = '<a href="{url}">こちら</a>'.format(url=url) 116 body += '<p><br>KULASISへのアクセスは{link}</p>'.format(link=link) 117 body += '</body>' 118 119 #署名部分 120 signature = '<br>-------------------------------------------<br>・このメールは送信専用です。<br>・不具合報告・配信停止は下のアドレスまで。<br>(管理人):kotasugisaki1268@gmail.com' 121 body += signature 122 123 if is_info_exist == True: #情報があった場合 124 #メールの設定 125 to_add = address #受信側のアドレス 126 from_add = config_ini.get('common', 'bot_mail') #送信側のアドレス 127 password = config_ini.get('common', 'bot_mailpass') #送信側アドレスのパスワード 128 subject = 'KULASIS新情報掲載のお知らせ' #件名 129 130 #処理が正常に終了した場合の完了ログ 131 sys.stdout.write('{}:スクリプトが正常に実行されました、新しいお知らせがあります'.format(section_name)) 132 133 #MIME形式でメールを作成 134 msg = MIMEMultipart() 135 msg['Subject'] = subject 136 msg['From'] = from_add 137 msg['To'] = to_add 138 msg['Date'] = formatdate() 139 #msg['Bcc'] = ', '.join(to_list) 140 msg.attach(MIMEText(body, 'html')) 141 142 #SMTPサーバーに接続してメールを送信 143 smtp_obj = smtplib.SMTP('smtp.gmail.com', 587) 144 smtp_obj.ehlo() 145 smtp_obj.starttls() 146 smtp_obj.login(from_add, password) 147 smtp_obj.send_message(msg) 148 smtp_obj.quit() 149 150 else: #情報がない場合 151 current_datetime = datetime.now() 152 message = current_datetime.strftime("新しい情報はありません") 153 #処理が正常に終了した場合の完了ログ 154 sys.stdout.write('{}:スクリプトが正常に実行されました、{}'.format(section_name,message)) 155 156 #エラーが発生した場合のエラーログ 157 except Exception as e: 158 sys.stdout.write('エラーが発生しました: %s' % str(e))
試したこと
- chromedriverのバージョン確認&再インストール
補足情報(FW/ツールのバージョンなど)
cloud functionsへアップロードするzipファイルには以下のファイルが入っています。
- main.py
- requirements.txt → seleniumとbeutifulsoup4のみ記載
- kulasis.ini
- chrome driver → 114.0.5735.90
あなたの回答
tips
プレビュー