前提・実現したいこと
AWS LambdaでIT用語のクローリング・スクレイピングを行い、PDFファイルにまとめるプログラムを作成しています。
仕様
・これは別のLambda関数から同期呼び出しを受けて動くプログラムです。
・別プログラムで得たjsonファイル(IT用語と推測されるキーフレーズ集)を取得します。
今回はデバッグ用に作った仮のファイルをS3からダウンロードして使用するものとします。
・入手したjsonファイルは該当箇所を抜き出してリスト型変数に格納されます。
・リスト型変数を使ってIT用語辞典から個別にキーフレーズを検索しキーフレーズの意味を辞書型で記録します。
・結果が存在しない、あるいは検索結果が不適切だった場合後程検索できるようにgoogleの検索結果URLを生成します。
・PDFファイルを生成し以上のことをぺージを分けて書き込みます。(こちらは動作することを確認したので今回は省略します)
発生している問題・エラーメッセージ
検索したいキーフレーズである文字列(str)を検索窓にsend_keys()しているのにdict,つまり辞書型として認識されAttributeErorrが返ってきてしまいます。
こちらが該当する周辺の行です。
python
1 for ph in v: 2 input_element = driver.find_element_by_class_name("gsib_a") 3 input_element.send_keys(f"{ph}") #エラー箇所 4 input_element.send_keys(Keys.RETURN)
類似した症状が無いか検索をしたのですが私が見た限りではありませんでした。
しかもAnacondaの開発環境では問題なく動くことが分かっています。
有識者の中で類似の事例や解決策を知っている方どうかご教示願います。
エラー文全文
Executionresults
1Response 2{ 3 "errorMessage": "'dict' object has no attribute 'send_keys'", 4 "errorType": "AttributeError", 5 "stackTrace": [ 6 " File \"/var/task/lambda_function.py\", line 141, in lambda_handler\n input_element.send_keys(f\"{ph}\")\n" 7 ] 8} 9 10Function Logs 11START RequestId: (省略) Version: $LATEST 12a:[{'keyPhrases': ['デジタル・トランスフォーメーション時代', 'イノベーティブ', 'ソリューション', 'コンビタンス', '顧客管理', 'アジャイル', 'プロトタイプ開発', 'ローンチ', 'パートーナー', '価値創造', '当社', '事', '知識', 'スキル', 'グローバル', '多様性', 'ビジネス', '人財'], 'id': '1', 'warnings': []}] 13c:{'keyPhrases': ['デジタル・トランスフォーメーション時代', 'イノベーティブ', 'ソリューション', 'コンビタンス', '顧客管理', 'アジャイル', 'プロトタイプ開発', 'ローンチ', 'パートーナー', '価値創造', '当社', '事', '知識', 'スキル', 'グローバル', '多様性', 'ビジネス', '人財'], 'id': '1', 'warnings': []} 14v:['デジタル・トランスフォーメーション時代', 'イノベーティブ', 'ソリューション', 'コンビタンス', '顧客管理', 'アジャイル', 'プロトタイプ開発', 'ローンチ', 'パートーナー', '価値創造', '当社', '事', '知識', 'スキル', 'グローバル', '多様性', 'ビジネス', '人財'] 15デジタル・トランスフォーメーション時代 16イノベーティブ 17ソリューション 18コンビタンス 19顧客管理 20アジャイル 21プロトタイプ開発 22ローンチ 23パートーナー 24価値創造 25当社 26事 27知識 28スキル 29グローバル 30多様性 31ビジネス 32人財 33ph:デジタル・トランスフォーメーション時代 34変数型:<class 'str'> 35[ERROR] AttributeError: 'dict' object has no attribute 'send_keys' 36Traceback (most recent call last): 37 File "/var/task/lambda_function.py", line 141, in lambda_handler 38 input_element.send_keys(f"{ph}") 39END RequestId: (省略) 40REPORT RequestId: (省略) Duration: 19843.01 ms Billed Duration: 19844 ms Memory Size: 800 MB Max Memory Used: 581 MB 41
該当のソースコード(クローリング・スクレイピングまで)
Python
1from selenium import webdriver 2from selenium.webdriver import Chrome, ChromeOptions, Remote 3from selenium.webdriver.common.keys import Keys 4#import chromedriver_binary 5 6from reportlab.lib.units import mm 7from reportlab.pdfgen import canvas 8from reportlab.lib.pagesizes import A4, portrait 9from reportlab.pdfbase import pdfmetrics 10from reportlab.pdfbase.ttfonts import TTFont 11from reportlab.pdfbase.cidfonts import UnicodeCIDFont 12 13import urllib.parse 14import os 15import boto3 16import json 17import shutil 18import time 19 20#イメージファイルを/tmp/上に移動させるプログラム 21def move_bin( 22 fname: str, src_dir: str = "/var/task/bin", dest_dir: str = "/tmp/bin" 23) -> None: 24 if not os.path.exists(dest_dir): 25 os.makedirs(dest_dir) 26 dest_file = os.path.join(dest_dir, fname) 27 shutil.copy2(os.path.join(src_dir, fname), dest_file) 28 os.chmod(dest_file, 0o775) 29 30 31def lambda_handler(event,content): 32 33 s3 = boto3.client("s3") 34 bucket = event["bucket"] 35 now=event["time_stamp"] 36 37 move_bin("headless-chromium","/opt/headless/python/bin/") 38 move_bin("chromedriver","/opt/headless/python/bin/") 39 #Lambda上で動かすためのオプション 40 options = ChromeOptions() 41 options.add_argument("--headless") 42 options.add_argument("--disable-gpu") 43 options.add_argument("--hide-scrollbars") 44 options.add_argument("--single-process") 45 options.add_argument("--ignore-certificate-errors") 46 options.add_argument("--window-size=880x996") 47 options.add_argument("--no-sandbox") 48 options.add_argument("--homedir=/tmp") 49 options.binary_location = "/tmp/bin/headless-chromium" 50 driver = webdriver.Chrome("/tmp/bin/chromedriver",chrome_options=options) 51 52 #作業用ディレクトリを作成(/tmp/HHMMSS/) 53 work_dir="/tmp/"+now+"/" 54 if not os.path.exists(work_dir): 55 os.mkdir(work_dir) 56 57 #印字用フォントの設定(第1引数:フォント、第2引数:サイズ) 58 #フォントをS3から作業用ディレクトリに落とす(layerから落とすよう後程変更する) 59 s3.download_file(bucket,"meiryo.ttc",work_dir+"meiryo.ttc") 60 #フォントの読み込み 61 pdfmetrics.registerFont(TTFont("Meiryo", work_dir+"meiryo.ttc")) 62 #pdfmetrics.registerFont(TTFont("HGRGE", "./HGRME.TTC")) 63 64 #lambdaのディレクトリを取得 65 #lambdaの作業ディレクトリである/tmp/ディレクトリにパスを通す 66 file = "sample.pdf" 67 file_path =work_dir+file 68 69 #cc = canvas.Canvas(file) 70 71 #/tmp/HHMMSS/sample.pdf 72 73 #xに初期値を設定 74 x=40 #座標600が最大 75 y=800 #座標840が最大 76 s="" 77 78 #空のPDFファイルを作成 79 page = canvas.Canvas(file_path, pagesize=portrait(A4)) 80 81 d={} 82 83 #キーフレーズのファイルを読込 84 #デバッグ用jsonファイル 85 dummy_json_key ="Static_json/dummyjson" 86 s3.download_file(bucket,dummy_json_key,work_dir+"key.json") 87 88 with open (work_dir+"key.json",mode="r") as f: 89 d=json.load(f) 90 91 92 a=d["documents"[:]] 93 print(f"a:{a}") 94 c=a[0] 95 print(f"c:{c}") 96 v=c["keyPhrases"] 97 print(f"v:{v}") 98 99 for phrase in v: 100 print(phrase) 101 102 count=0 103 page.setFont("Meiryo", 20) 104 c=0 105 length=len(v) 106 page.setStrokeColorRGB(1.0, 0.0, 0.0) 107 108 # キーフレーズの意味検索 109 kp = 0 110 111 112 # IT用語辞典のトップ画面を開く。 113 driver.get('https://e-words.jp/') 114 time.sleep(5) 115 116 # タイトルにe-wordsが含まれていることを確認する。 117 assert 'IT用語辞典 e-Words' in driver.title 118 119 kaisetu_dict = {} 120 url_dict = {} 121 ph_dict = {} 122 kp = 0 123 u = 0 124 p = 0 125 126 ''' 127 文字化け確認用 128 driver.get_screenshot_as_file(work_dir+"check.png") 129 assertcheck=open(work_dir+"check.png","rb") 130 s3.put_object(Bucket=bucket,Key='check.png',Body=assertcheck) 131 assertcheck.close() 132 ''' 133 134 for ph in v: 135 input_element = driver.find_element_by_class_name("gsib_a") 136 input_element.send_keys(f"{ph}") 137 input_element.send_keys(Keys.RETURN) 138 time.sleep(5) 139 140 # タイトルにキーフレーズが含まれていることを確認する。 141 # assert 'python' in driver.title 142 143 # スクリーンショットを撮る。 144 #driver.save_screenshot('search_results.png') 145 146 # 検索結果を表示する。 147 for a in driver.find_elements_by_css_selector('main > div > div > div > div > div > div > div > div > div > div > div > div > div > div > a'): 148 # b = a.find_element_by_xpath('..') 149 # print(a.text) 150 b = a.get_attribute('href') 151 152 break 153 154 # 検索結果があった場合 155 kensaku = driver.find_elements_by_css_selector('main > div > div > div > div > div > div > div > div > div > div > div > div > div') 156 if kensaku[0].text != "一致する結果はありません": 157 158 # 一番上の検索結果を表示 159 driver.get(b) 160 time.sleep(5) 161 for c in driver.find_elements_by_css_selector('article > div > p'): 162 163 # 検索結果の吟味 164 cheak = ph in c.text 165 if cheak == False: 166 ph_dict[p] =ph 167 url = "https://www.google.com/search?q="+ph 168 url_dict[u] = url 169 u = u + 1 170 p = p + 1 171 print(url) 172 break 173 174 kaisetu = ph + ":" + c.text + "\n" 175 176 #辞書型配列を作る 177 kaisetu_dict[kp] = kaisetu 178 kp = kp + 1 179 print(kaisetu) 180 181 182 else: 183 driver.get('https://e-words.jp/') 184 time.sleep(1) 185 continue 186 187 driver.quit() # ブラウザーを終了する。 188(以下略)
試したこと
・適当な変数を用意し、(変数)=''.join(v)をした
・f文字列を使わずに表記した
・for文直前で明示的に宣言したりsend_keys()内でキャストしたりした
・変数を使わずsend_keys()内に直打ちをした
→いずれも同様のエラー
補足情報(FW/ツールのバージョンなど)
参考サイト
・【Python】AWS Lambdaでheadless chrome+seleniumを実行する方法
・AWS Lambdaで列車運行情報を定期的にLINEへ通知してみた【Python】
・Selenium API(逆引き)
各環境
・開発環境
ANACONDA
Python3.6,3.7
Chrome(非ヘッドレスモード)
Chrome-driver
selenium
reportlab(割愛)
・本番環境
AWS Lambda
Python3.7
Headless-Chromium
Chrome-driver
selenium
reportlab(割愛)
Layers
Amazon cloud9からEC2を利用しzipフォルダを作成
・Headless(Headless-Chromium及び対応するChromedriver格納)
・MakeNote(seleniumとReportlabs格納)
・Fonts(.fonts格納)
環境変数
・HOME = /opt/
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。