質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

タグ

特殊な記法により文書に埋め込む形で記述される付加情報をタグと呼びます。文書構造や書式、文字飾りなどを指示したり、画像や他の文書へのリンクを埋め込むことができる。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

Q&A

解決済

1回答

1576閲覧

Seleniumを使ってスクレイピングをしCSVリスト化したいのですが、正しいリスト化/タグの指定ができません。

HF0603

総合スコア12

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

タグ

特殊な記法により文書に埋め込む形で記述される付加情報をタグと呼びます。文書構造や書式、文字飾りなどを指示したり、画像や他の文書へのリンクを埋め込むことができる。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

0グッド

0クリップ

投稿2020/02/13 12:39

前提・実現したいこと

現在、以下のサイトの必要箇所をスクレイピングしてCSVリスト化しようと試みております。

対象サイト
https://travelersnavi.com/coupon/category/waribiki

並んでいる記事のタイトル・投稿された日付を取得したいのですが、
日付箇所のタグをどう指定すればいいのかがわかりません。

イメージ説明

該当のソースコード

Python

1from selenium import webdriver 2import chromedriver_binary 3import time 4import pandas as pd 5 6TITLE_LIST = [] 7DAY_LIST = [] 8 9browser = webdriver.Chrome() 10for num in range(1,3): 11 browser.get('https://travelersnavi.com/coupon/category/waribiki/page/{}'.format(num)) 12 13 campaign_title = browser.find_elements_by_tag_name('h3') 14 campaign_day = browser.find_elements_by_css_selector('.blog_info > p') 15 16 for title in campaign_title: 17 TITLE_LIST.append(title.text) 18 for day in campaign_day: 19 DAY_LIST.append(day.text) 20 time.sleep(5) 21 22print(TITLE_LIST) 23print(DAY_LIST) 24browser.close() 25 26df = pd.DataFrame() 27df['TITLE'] = TITLE_LIST 28df['DAY'] = DAY_LIST 29 30df 31 32df.to_csv('旅行キャンペーン一覧.csv',index=False)

発生している問題・エラーメッセージ①

printまでは可能なものの、
ValueError: Length of values does not match length of index
のエラーが出てしまいます。

--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-8-21a1eab37410> in <module> 25 df = pd.DataFrame() 26 df['TITLE'] = TITLE_LIST ---> 27 df['DAY'] = DAY_LIST 28 29 df ~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/frame.py in __setitem__(self, key, value) 3470 else: 3471 # set column -> 3472 self._set_item(key, value) 3473 3474 def _setitem_slice(self, key, value): ~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/frame.py in _set_item(self, key, value) 3547 3548 self._ensure_valid_index(value) -> 3549 value = self._sanitize_column(key, value) 3550 NDFrame._set_item(self, key, value) 3551 ~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/frame.py in _sanitize_column(self, key, value, broadcast) 3732 3733 # turn me into an ndarray -> 3734 value = sanitize_index(value, self.index, copy=False) 3735 if not isinstance(value, (np.ndarray, Index)): 3736 if isinstance(value, list) and len(value) > 0: ~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/construction.py in sanitize_index(data, index, copy) 610 611 if len(data) != len(index): --> 612 raise ValueError("Length of values does not match length of index") 613 614 if isinstance(data, ABCIndexClass) and not copy: ValueError: Length of values does not match length of index
これに対する仮説

以下の部分でタイトルの数と日付の数がリンクしておらず、
Dateframeへの格納が上手くできていないためのエラーと見ております。

df = pd.DataFrame() df['TITLE'] = TITLE_LIST df['DAY'] = DAY_LIST

これを解消してリスト化するためには、

  • DAY_LISTで不要に抽出してしまっている箇所を読み込んでこないよう抑制する
  • 逆にTITLE_LISTの不足分をNULLとして抽出するようにする

なのかと思いますが、こちらの方法がわかりません。

発生している問題・エラーメッセージ②

仮にエラーメッセージ①が解決したとしても、
このままのCSSセレクター指定だと、指定した日付以外のタグ付けテキストも一緒に抽出されてしまいます。
以下、printした時点での抽出結果です。

['東京ディズニーリゾート周辺ホテルに使える宿泊割引クーポン特集', 'USJ周辺ホテル予約に使える旅行クーポン特集', '北海道ふるさと割旅行クーポンで宿泊・ツアー割引', '箱根伊豆ふっこう割・旅行クーポンでホテル旅館の宿泊割引!観光復興応援', '楽天カーボン・オフセットキャンペーンクーポンで宿泊2,000円引|1名利用OK', '宮崎県ふるさと割旅行クーポンで宿泊割引', 'dトラベル宿泊dポイント7%増量、ふっこう割クーポン併用可', '鳥取・米子へのANAツアー旅行クーポンで最大6万円割引&レンタカーもお得', '滋賀県ふるさと割クーポンで旅行最大5,000円割引|大河ドラマ麒麟がくる放映', 'JTB・るるぶ・dトラベル全国厳選宿で使える旅行クーポン', '旅行クーポンサイト|ふっこう割・国内ホテル・ツアー割引情報まとめ'] ['2020/2/4 じゃらん, まとめ, インターネット予約, ヤフートラベル, 楽天トラベル', '2020/2/4 じゃらん, るるぶ, インターネット予約, ヤフートラベル, 楽天トラベル', '2020/2/3 るるぶ, インターネット予約', '2020/2/3 インターネット予約, 楽天トラベル', '2020/2/7 インターネット予約, 楽天トラベル', '2020/2/3 じゃらん, ふるさと割, インターネット予約', '2020/2/1 ', '2020/1/31 ふるさと割, インターネット予約, 楽天トラベル, 飛行機', '2020/1/31 るるぶ, インターネット予約', '2020/1/31 るるぶ, インターネット予約, ヤフー', '2020/2/13', '2020/2/13', '2020/2/13', '2020/2/12', '2020/2/12']

今回抽出したい要素は「#text」ですが、どう指定すればここのみ抜き出せるのかがわからないです。

これに対する仮説

以下サイトを参考に要素を指定しました。

https://kurozumi.github.io/selenium-python/locating-elements.html

こちらを拝見する限りだと、
タグを指定できない場合、XPathを使用すると描かれており、
もし現状タグ指定ができないのであれば、XPathを使用する方法で解決するのでしょうか?

XPathを使用する主な理由の1つは、探したい要素に適切なIDまたは名前属性がない場合です。XPathを使用すると、絶対的な用語(アドバイスされていない)で要素を見つけることも、idまたはname属性を持つ要素に関連付けることができます。XPathロケータを使用して、idやname以外の属性を使用して要素を指定することもできます。

まとめ

一つのケースで二つ質問する形となってしまい大変恐縮なのですが、
ゴールとしては冒頭挙げた通り、「並んでいる記事のタイトル・投稿された日付」の二箇所を取得してCSVリスト化できれば問題ございません。

わかりづらい点等あるかと思いますが、ご教授いただけますと幸いです。

補足情報(FW/ツールのバージョンなど)

開発環境/使用ライブラリ
・macOS Mojave 10.14.6
・python3.7
・anaconda3 jupyter notebook
・Googlechrome Version: 76.0.3809.126.0
・Selenium (chromedriver-binary==79.0.3945.36.0)
・pandas

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

pandasエラー

開発者ツールに

Javascript

1document.getElementsBytagName('h3') 2document.getElementsByClassName('blog_info')

とそれぞれ打ち込むと11個の配列と15個の配列が出てきます。
4つの差は何かというと「お得に旅する最新情報」です。

なので正解は以下の通りです。

python

1main_articles = browser.find_element_by_tag_name('main') 2campaign_title = main_tag.find_elements_by_tag_name('h3') 3campaign_day = main_tag.find_elements_by_css_selector('.blog_info > p')

日付のみを取得できない

こんなもんsplitなり正規表現なりで切ってやればいいだけです。

python

1import re 2 3for day in campaign_day: 4 nen = day.split('/')[0] 5 tsuki = day.split('/')[1] 6 hi = re.sub('\D', '', day.split('/')[2]) 7 DAY_LIST.append(nen + '/' + tsuki + '/' hi)

投稿2020/02/14 02:38

shirai

総合スコア1290

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HF0603

2020/02/15 01:55

ご丁寧な回答ありがとうございます。 pandasについては頂いた形で解決しました。 ※エラーが出たのでmain_tag.をmain_articlesに変えたところ抽出できました。 main_articles = browser.find_element_by_tag_name('main') campaign_title = main_articles.find_elements_by_tag_name('h3') campaign_day = main_articles.find_elements_by_css_selector('.blog_info > p') 正規表現ですが、Webelementのattributeエラーが出てしまいます。 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-43-8a9061cbdf94> in <module> 19 TITLE_LIST.append(title.text) 20 for day in campaign_day: ---> 21 nen = day.split('/')[0] 22 tsuki = day.split('/')[1] 23 hi = re.sub('\D', '', day.split('/')[2]) AttributeError: 'WebElement' object has no attribute 'split' 以下のサイトなどを参考に調べてみましたが、すべてを理解しきれず… https://qiita.com/VDiUZnM1hUIzKvb/items/4d18ca1d781ed6ff2b2f 見当つきそうな要因をご教授くだされば幸いです。
shirai

2020/02/16 14:49

すみません思いっきり間違えていました。 day.text.split('/')[0]でいけると思います。
HF0603

2020/02/17 06:34

Shirai様、御丁寧にありがとうございました。 無事解決致しました。 ※初学者につき初めてのteratail投稿でしたが、的確な回答いただき感動してしまいました。引き続き精進してまいります。本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問