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

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

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

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

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Python

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

selenium

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

Q&A

解決済

1回答

1966閲覧

Pythonスクレイピング:正規表現での「年」の取り扱いについて

gomasan

総合スコア96

スクレイピング

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

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Python

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

selenium

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

0グッド

0クリップ

投稿2020/08/30 13:29

編集2020/08/30 13:31

前提・実現したいこと

Pythonでサイトの口コミをスクレイピングしています。
また、結果をcsvに抽出しています。
ライブラリ:selenium

発生している問題

正規表現を使って、昨日の日付のみ抽出したいのですが、
2019年の口コミになると以下の通りエラーとなります。

Traceback (most recent call last): File "/Users/xxx/Desktop/ファイル/choice/xxx.py", line 66, in <module> review_date = str2date(review_date_str) File "/Users/xxx/Desktop/ファイル/choice/xxx.py", line 9, in str2date tar_date = datetime(int(result[1]), int(result[2]), int(result[3])) TypeError: 'NoneType' object is not subscriptable

該当のソースコード

コード全体

python

1from selenium import webdriver 2import time 3import csv 4import re 5from datetime import datetime, date, timedelta 6 7def str2date(date_str): 8 result = re.search(r'(\d{4})年(\d{1,2})月(\d{1,2})日', date_str) 9 tar_date = datetime(int(result[1]), int(result[2]), int(result[3])) 10 print(result[1]) 11 return tar_date 12 13def is_yesterday(tar_date): 14 now = datetime.now() 15 yesterday = now - timedelta(days=1) 16 yesterday_str = datetime.strftime(yesterday, '%Y-%m-%d') 17 tar_date_str = datetime.strftime(tar_date, '%Y-%m-%d') 18 19 return tar_date_str == yesterday_str 20 21# 現在の時刻を年、月、日、時、分、秒で取得 22time_ = datetime.today().strftime("%Y%m%d") 23 24csv_file_name = "choice" + time_ + ".csv" 25f = open(csv_file_name, 'w',encoding='cp932', errors='ignore') 26 27#ファイルへの書き込み 28writer = csv.writer(f, lineterminator='\n') 29 30#headerの指定 31csv_header = ["商品名", "投稿日","レビュー"] 32writer.writerow(csv_header) 33 34# ブラウザを開く 35browser = webdriver.Chrome() 36# URLを開く 37url = "https://www.furusato-tax.jp/city/product/01219?incsoldout=1&sort=11&page=1" 38browser.get(url) 39time.sleep(1.0) 40elems_box = browser.find_element_by_css_selector('.result-search') 41elems = elems_box.find_elements_by_css_selector('.card-product') 42review_score_src_list = [] 43contain_review_links = [] 44review_links = [] 45for elem in elems[4:6]: 46 time.sleep(1.0) 47 # 3のaタグがclass = 'card-product__comment'である場合のみ、先に進む 48 card_products = elem.find_elements_by_css_selector('a')[2] 49 elem_card_products = card_products.get_attribute('class') 50 if elem_card_products != 'card-product__comment': 51 continue 52 else: 53 contain_review_links.append(card_products.get_attribute('href')) 54 55for contain_review_link in contain_review_links: 56 time.sleep(1.0) 57 browser.get(contain_review_link) 58 review_lists = browser.find_elements_by_css_selector('.review-list__content') 59 for review_list in review_lists: 60 csv_list = [] 61 product_name = review_list.find_element_by_css_selector('.review-list__name').text[3:] 62 review_date_str = review_list.find_element_by_css_selector('.review-list__date').text[4:14] 63 review_date = str2date(review_date_str) 64 review_body = review_list.find_element_by_css_selector('.review-list__text').text.replace('\n','') 65 if is_yesterday(review_date): 66 csv_list.append(product_name) 67 csv_list.append(review_date) 68 csv_list.append(review_body) 69 writer.writerow(csv_list) 70 71f.close() 72browser.close()

エラー箇所

python

1line9: 2tar_date = datetime(int(result[1]), int(result[2]), int(result[3])) 3 4line66: 5review_date = str2date(review_date_str)

試したこと

print(result[1])

で年をprintした結果、

python

12020 22020 32020 42020 52020 62020 72020 8Traceback (most recent call last): 9 File "/Users/xxx/Desktop/ファイル/choice/xxx.py", line 66, in <module> 10 review_date = str2date(review_date_str) 11 File "/Users/xxx/Desktop/ファイル/choice/xxx.py", line 9, in str2date 12 tar_date = datetime(int(result[1]), int(result[2]), int(result[3])) 13TypeError: 'NoneType' object is not subscriptable

となります。

理想の結果としては、

python

12020 22020 32020 42020 52020 62020 72020 82019 92019 102019

です。

正規表現の書き方の問題なのか、調べてもこの年の取り扱いがいまいち分からず...
ご教示いただけますと幸いです。
よろしくお願いいたします。

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

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

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

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

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

otn

2020/08/30 13:47

どこから期待通りでなくなっているのか、遡って調べましょう。
guest

回答1

0

ベストアンサー

ええと、これは2019のマッチに失敗しているわけではありません。年月日の文字列を切り取るスライスに問題があります。

Python

1review_date_str = review_list.find_element_by_css_selector('.review-list__date').text[4:14]

.review-list__dateクラスのテキストには「投稿日:2019年12月15日 12:17」といった形式の文字列が格納されています。

現在のスライス[4:14]だと、「12月15日」のように、月と日の数値がともに2桁の場合、スライスした文字列に「日」が含まれないのです。その結果、str2dateでの正規表現のマッチに失敗し、resultNoneになります。当然、result[1]などを参照すれば、提示されているエラーが発生します。

2020年のデータはまだ月の数値が2桁のものが存在しないため、2019年のデータになってはじめて問題が露呈したというわけ。

対策としては、スライスを[4:]に修正して、

Python

1review_date_str = review_list.find_element_by_css_selector('.review-list__date').text[4:]

のようにすれば、「12月15日」などでも問題なくマッチするようになります。修正前とは違って、時刻の文字列までスライスで得られますが、($を使っていないので)正規表現のマッチに問題は起きません。

投稿2020/08/30 14:04

編集2020/08/31 01:10
Daregada

総合スコア11990

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

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

gomasan

2020/08/31 00:57

ありがとうございます!!言われて確かにと納得しました..とても丁寧な解説をありがとうございます。よく理解できました。本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問