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

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

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

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

CSV

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

Webサイト

一つのドメイン上に存在するWebページの集合体をWebサイトと呼びます。

Python

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

selenium

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

Q&A

解決済

1回答

2055閲覧

pythonスクレイピング:pickleの使い方について

gomasan

総合スコア96

スクレイピング

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

CSV

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

Webサイト

一つのドメイン上に存在するWebページの集合体をWebサイトと呼びます。

Python

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

selenium

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

0グッド

0クリップ

投稿2020/09/10 01:13

編集2020/09/10 09:42

前提・実現したいこと

Pythonでwebサイトのスクレイピングをし、csvに抽出しています。
前回抽出していないものを抽出し、csvに書き込むということをしたいです。
(本来は昨日の日付で抽出したいのですが、数日後に口コミ反映がされる場合が多いため、「抽出したことがないもの」という条件に切り替えています。)

下の内容でいうと、
・全商品の最終投稿日付(last_update_list)を取得
・次プログラムを回すときにlast_update_listを参照して、追記するレビューリストを作成
・last_update_listを保存・読み込み

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

pickleを使って前回内容を記憶、読み出しをしようと思っているのですが、うまくいきません。。

Traceback (most recent call last): File "/Users/myname/Desktop/sample.py", line 136, in <module> main(False) File "/Users/myname/Desktop/sample.py", line 30, in main pickle.load(fl) _pickle.UnpicklingError: invalid load key, 'f'.

以下にコード全体を記載しますが、エラー箇所は以下の通りです。

line30 pickle.load(fl) line136(コードの最終行) main(False)

該当のソースコード

sample.py

python

1 2from selenium import webdriver 3import time 4import csv 5import re 6from datetime import datetime, date, timedelta 7from selenium.webdriver.common.keys import Keys 8from selenium.webdriver.chrome.options import Options 9import sys 10import pickle 11 12 13def str2date(date_str): 14 result = re.search(r'(\d{4})年(\d{1,2})月(\d{1,2})日', date_str) 15 tar_date = datetime(int(result[1]), int(result[2]), int(result[3])) 16 return tar_date 17 18def is_bf_yesterday(tar_date, last_update_date): 19 # now = datetime.now() 20 # yesterday = now - timedelta(days=1) 21 last_update_date_str = datetime.strftime(last_update_date, '%Y-%m-%d') 22 tar_date_str = datetime.strftime(tar_date, '%Y-%m-%d') 23 24 return tar_date_str > last_update_date_str 25 26def main(is_init): 27 28 # rbモードでファイルを読み込み 29 fl = open('pickle.binaryfile','rb') 30 pickle.load(fl) 31 # csv_file_name 32 csv_file_name = "/Users/myname/Desktop/" + "satofuru" + ".csv" 33 f = open(csv_file_name, 'a',encoding='cp932', errors='ignore') 34 35 #ファイルへの書き込み 36 writer = csv.writer(f, lineterminator='\n') 37 38 #headerの指定 39 csv_header = ["商品名", "投稿日","評価", "レビュー"] 40 writer.writerow(csv_header) 41 42 # ブラウザを開く 43 last_update_dict = {} 44 browser = webdriver.Chrome('/usr/local/bin/chromedriver') 45 for page in range(1, 4): 46 print('webdriver ok') 47 # URLを開く 48 url = "https://www.xxx.php?=60&p={}".format(page) 49 browser.get(url) 50 time.sleep(1.0) 51 elems = browser.find_elements_by_class_name('ItemList__link') 52 contain_review_links = [] 53 review_links = [] 54 date_src_list = [] 55 for elem in elems: 56 #各elemからimgタグのsrcを一覧で出す 57 review_score_src = elem.find_element_by_class_name('ItemList__xxx').find_element_by_tag_name('img').get_attribute('src') 58 if review_score_src == 'https://www.xxx.jp/static/xxx/images/pic_star0.png': 59 pass 60 else: 61 # リンクを一覧で取得 62 contain_review_links.append(elem.get_attribute('href')) 63 64 for contain_review_link in contain_review_links: 65 time.sleep(1.0) 66 browser.get(contain_review_link) 67 review_list_src = browser.find_element_by_css_selector('.xxx').get_attribute('href') 68 browser.get(review_list_src) 69 time.sleep(2.0) 70 71 pr_name = browser.find_element_by_css_selector('.xxx').text 72 73 review_table = browser.find_elements_by_css_selector('.xxx')[2] 74 75 review_lists = review_table.find_elements_by_css_selector('tr')[1:] 76 for i, review_list in enumerate(review_lists): 77 # review_listで投稿日が昨日であれば、「続きを読む」のリンクを取得してcsvに抽出する 78 review_lists_date = review_list.find_elements_by_css_selector('td')[0].text 79 date_src_list.append(review_lists_date) 80 for date_src in date_src_list: 81 elem_date = str2date(date_src) 82 if is_init: 83 if i == 0: 84 last_update_dict[pr_name] = elem_date 85 review_link_list = review_list.find_element_by_css_selector('a').get_attribute('href') 86 review_links.append(review_link_list) 87 elif is_bf_yesterday(elem_date, last_update_dict[pr_name]): 88 # 昨日の日付の場合はhrefリンクを取得し、リストにする(review_links) 89 review_link_list = review_list.find_element_by_css_selector('a').get_attribute('href') 90 review_links.append(review_link_list) 91 92 93 94 for review_link in review_links: 95 print('review_link ok') 96 csv_list = [] 97 time.sleep(2.0) 98 browser.get(review_link) 99 elem_product_name = browser.find_element_by_css_selector('.product-name a') 100 product_name = elem_product_name.text 101 review_box = browser.find_element_by_css_selector('.review_info') 102 review_elems = review_box.find_elements_by_css_selector('tr td') 103 review_date = review_elems[0].text 104 review_score = 0 105 imgs = review_box.find_elements_by_css_selector('.valuation img') 106 for img in imgs: 107 src = img.get_attribute("src") 108 if src == 'https://www.xxx.jp/xxx/images/common/star_a.png': 109 review_score += 1 110 review = review_box.find_element_by_css_selector('.cxxx').text 111 csv_list.append(product_name) 112 csv_list.append(review_date) 113 csv_list.append(review_score) 114 csv_list.append(review) 115 writer.writerow(csv_list) 116 117 f.close() 118 browser.close() 119 120if __name__ == "__main__": 121 if len(sys.argv) >= 2: 122 if sys.argv[1] == 'init': 123 main(is_init=True) 124 else: 125 main(False)

pickle.binaryfile

fl = open('pickle.binaryfile','wb') pickle.dump(last_update_dict, fl) fl.close

試したこと

pythonファイルのmain関数でまず読み込みをし、その結果をpickle.binaryfileで保存(したつもりです..)

pickleを今回初めて使いまして、使い方が全然違うかもしれません...
アドバイスいただけますと幸いです。よろしくお願いいたします。

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

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

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

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

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

1T2R3M4

2020/09/10 02:01

何に使用するのかわかりませんが、著作権等問題ないですか。
gomasan

2020/09/10 02:08

はい、一応サイトと会社間でのやりとりとなっておりまして、robots.txtにも沿った形となっています。
nto

2020/09/10 05:21 編集

エラーではこの時点でbinaryfileを既に読み込む事に失敗している為、おそらく前回保存に問題がありです。 バイナリファイルの中身は正常ですか? 宜しければ掲載が可能なのであればエディタ等で開いて掲載頂けますでしょうか。
gomasan

2020/09/10 05:34

nto様 ありがとうございます。バイナリファイルですが、 import pickle with open('pickle.binaryfile', 'wb') as web: pickle.dump(last_update_dict , fl) しか書いておりません。フォルダを分けて格納する空フォルダが必要と認識しているためです。 ちなみにいただいたwith構文では、同じエラー箇所が、「_pickle.UnpicklingError: could not find MARK」という内容に変更になりました。。
gomasan

2020/09/10 05:34

必要であれば画面もお送りいたします。
nto

2020/09/10 05:48

掲載頂いているものはバイナリファイルを生成する為の実行コードであり、それはバイナリファイルではありません。 pickleによるバイナリファイルとは、pickle.dump()を実行する事によってファイルが生成されるものであり、通常はコードが記述されているものではありません。
gomasan

2020/09/10 06:35

なるほど、、失礼いたしました。バイナリファイルの中身の確認方法が分からないのですが、sample.pyファイルのエディタ画像をお送りすればよろしいでしょうか?
guest

回答1

0

ベストアンサー

最終的にはこの様な構造でコーディングしていけば良いと思います。
コードを実行する時に、pickleを読み取るかどうかはgomasan様の中のルールや条件というものがあるでしょうから、それに従ってif文などで処理してください。(初回起動である場合にも読み取る必要ない)

そしてコードを動かし終わり最後に収集したデータをpickle化する場合にpickle_save()で保存するという形です。

python

1file_name = 'pickle.binaryfile' 2def main(is_init): 3 if pickleを読み取るか読み取らないかの条件式: 4 last_update_dict = pickle_read() 5 6 # 中略 ここに行いたい処理 7 8 # 最後に今回抽出&上書きしたデータをdumpする。 9 pickle_save(last_update_dict) 10 11def pickle_read(): 12 with open(file_name, 'rb') as f: 13 p = pickle.load(f) 14 return p 15 16def pickle_save(data): 17 with open(file_name, 'wb') as f: 18 pickle.dump(data, f) 19 print('Done!')

追記

思っている通りの動作になっているかはわかりかねますが
以下で、正常にpickle化・非pickle化しコードを正常に運転いただけるかと思います。
コマンドライン引数にinitで初回はpickleの読み込みをしない仕様になっております。
次回以降は引数を与えない事で、初めに非pickle化され、データが追記されていきます。

python

1from selenium import webdriver 2import time 3import csv 4import re 5from datetime import datetime, date, timedelta 6from selenium.webdriver.common.keys import Keys 7from selenium.webdriver.chrome.options import Options 8import sys 9import pickle 10 11 12 13def main(is_init): 14 if not is_init: 15 last_update_dict = pickle_read() 16 else: 17 last_update_dict = {} 18 print(last_update_dict) 19 20 csv_file_name = "satofuru" + ".csv" 21 f = open(csv_file_name, 'a',encoding='cp932', errors='ignore') 22 23 #ファイルへの書き込み 24 writer = csv.writer(f, lineterminator='\n') 25 csv_header = ["商品名", "投稿日","評価", "レビュー"] 26 writer.writerow(csv_header) 27 28 # 中略 ここに行いたい処理 29 for i in range(3, 4): 30 page_scraping(i, is_init, last_update_dict, writer) 31 32 f.close() 33 browser.close() 34 35 # 最後に今回抽出&上書きしたデータをdumpする。 36 pickle_save(last_update_dict) 37 38def page_scraping(page, is_init, last_update_dict, writer): 39 url = "https://www.satofull.jp/products/list.php?s4=%E5%8C%97%E6%B5%B7%E9%81%93&s3=%E7%B4%8B%E5%88%A5%E5%B8%82&sort=rev_cnt&cnt=60&p={}".format(page) 40 browser.get(url) 41 time.sleep(1.0) 42 elems = browser.find_elements_by_class_name('ItemList__link') 43 contain_review_links = [] 44 review_links = [] 45 # date_list = [] 46 date_src_list = [] 47 for elem in elems: 48 #各elemからimgタグのsrcを一覧で出す 49 review_score_src = elem.find_element_by_class_name('ItemList__review').find_element_by_tag_name('img').get_attribute('src') 50 if review_score_src == 'https://www.satofull.jp/static/master/packages/default/images/pic_star0.png': 51 pass 52 else: 53 # リンクを一覧で取得 54 contain_review_links.append(elem.get_attribute('href')) 55 56 for contain_review_link in contain_review_links: 57 time.sleep(1.0) 58 browser.get(contain_review_link) 59 # 商品ページからレビュー一覧へ 60 review_list_src = browser.find_element_by_css_selector('.V1808-dReview__head__btn a').get_attribute('href') 61 browser.get(review_list_src) 62 time.sleep(2.0) 63 64 pr_name = browser.find_element_by_css_selector('.product-name a').text 65 66 # '.table_style_01' = レビュー一覧ページ内のレビューリストの大枠 67 review_table = browser.find_elements_by_css_selector('.table_style_01')[2] 68 # review_lists = レビューリストの2番目からfor文を回す(1番目は項目のtr) 69 review_lists = review_table.find_elements_by_css_selector('tr')[1:] 70 for i, review_list in enumerate(review_lists): 71 # review_listで投稿日が昨日であれば、「続きを読む」のリンクを取得してcsvに抽出する 72 review_lists_date = review_list.find_elements_by_css_selector('td')[0].text 73 date_src_list.append(review_lists_date) 74 for date_src in date_src_list: 75 elem_date = str2date(date_src) 76 if is_init: 77 if i == 0: 78 last_update_dict[pr_name] = elem_date 79 review_link_list = review_list.find_element_by_css_selector('a').get_attribute('href') 80 review_links.append(review_link_list) 81 elif is_bf_yesterday(elem_date, last_update_dict[pr_name]): 82 # 昨日の日付の場合はhrefリンクを取得し、リストにする(review_links) 83 review_link_list = review_list.find_element_by_css_selector('a').get_attribute('href') 84 review_links.append(review_link_list) 85 86 for review_link in review_links: 87 print('review_link ok') 88 csv_list = [] 89 time.sleep(2.0) 90 browser.get(review_link) 91 elem_product_name = browser.find_element_by_css_selector('.product-name a') 92 product_name = elem_product_name.text 93 review_box = browser.find_element_by_css_selector('.review_info') 94 review_elems = review_box.find_elements_by_css_selector('tr td') 95 review_date = review_elems[0].text 96 review_score = 0 97 imgs = review_box.find_elements_by_css_selector('.valuation img') 98 for img in imgs: 99 src = img.get_attribute("src") 100 if src == 'https://www.satofull.jp/static/master/packages/default/images/common/star_a.png': 101 review_score += 1 102 review = review_box.find_element_by_css_selector('.comment_area').text 103 csv_list.append(product_name) 104 csv_list.append(review_date) 105 csv_list.append(review_score) 106 csv_list.append(review) 107 writer.writerow(csv_list) 108 109def str2date(date_str): 110 result = re.search(r'(\d{4})年(\d{1,2})月(\d{1,2})日', date_str) 111 tar_date = datetime(int(result[1]), int(result[2]), int(result[3])) 112 return tar_date 113 114def is_bf_yesterday(tar_date, last_update_date): 115 # now = datetime.now() 116 # yesterday = now - timedelta(days=1) 117 last_update_date_str = datetime.strftime(last_update_date, '%Y-%m-%d') 118 tar_date_str = datetime.strftime(tar_date, '%Y-%m-%d') 119 120 return tar_date_str > last_update_date_str 121 122def pickle_read(): 123 with open(fine_name,'rb') as f: 124 p = pickle.load(f) 125 return p 126 127def pickle_save(data): 128 with open(fine_name, 'wb') as f: 129 pickle.dump(data, f) 130 print('Done!') 131 132if __name__ == "__main__": 133 fine_name = 'pickle.binaryfile' 134 browser = webdriver.Chrome() 135 if len(sys.argv) >= 2: 136 if sys.argv[1] == 'init': 137 main(is_init=True) 138 else: 139 main(False)

投稿2020/09/10 06:58

編集2020/09/10 10:09
nto

総合スコア1438

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

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

gomasan

2020/09/10 08:25

ありがとうございます...!! fをcsvに使っているため、言われた内容をflで記載してみたのですが、 「_pickle.UnpicklingError: could not find MARK」となります...エラー箇所は、 line 146, in <module> main(False) line 29, in main last_update_dict = pickle_read() line 132, in pickle_read p = pickle.load(fl) ちなみにですが、教えていただいた内容へ変更する際、pickle.binaryfileは何を記載すればよろしいでしょうか?現在は、 import pickle with open('pickle.binaryfile', 'wb') as web: pickle.dump(last_update_dict , fl) となっております。
nto

2020/09/10 08:36

バイナリファイルはpythonのコード上で生成及び読み取りするものであり 何かをご自身で記述す必要は一切ありません。 現在のそのpickle.binaryfileは正常なものではない様なので削除してしまって構いません。 そして今回のコメントにあるエラーが出る原因としては、ファイルが正常ではないのに読み込みをしようとしたからエラーが出ているわけであり、初回はバイナリファイルを読み取る必要はないのでpickle_read()は実行させずに全体コードを実行させて下さい。 そうする事で改めて正常なpickle.binaryfileが生成されるかと思います。 次回以降のコードの実行時にも、正常にpickle_read()にて読み取る事が出来る様になりエラーは出なくなると思います。
gomasan

2020/09/10 09:31

> バイナリファイルはpythonのコード上で生成及び読み取りするものであり何かをご自身で記述す必要は一切ありません。 →なるほど、やっと理解できました。。。最初に自分でファイルを作っていました。。そういうことなのですね。ファイルを削除+初回をpickle_read()させずに動かしたところ、ブラウザ表示までいきました..(T T)!また別のエラーが出ていますが、こちら一旦自分でやってみようと思います。いつも本当にありがとうございます!!
nto

2020/09/10 10:10

改めてサンプルコードを掲載させていただきました。 また、pickleの書き込み時のオプションが'w'となっていた所を'wb'へ修正致しました。 サンプルコードの仕様については追記させて頂いております。お確かめ下さい。
nto

2020/09/10 10:16

pickleというものに関して私自身も初めて触れたものでしたので勉強になりました。 以下のページがpickleの使用に関して非常に参考になりました。 https://techacademy.jp/magazine/15826
gomasan

2020/09/10 15:12

ご丁寧にありがとうございます...(T T) 参考記事、拝見しました。とてもわかりやすいです。。! 今回もとても勉強になりました。本当にありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問