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

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

新規登録して質問してみよう
ただいま回答率
85.35%
DataSet

DataSetは、ADO.NETアーキテクチャのコンポーネントです。データベースから取得したレコードをメモリ領域に格納するクラスを指します。データの保持やテーブル間のリレーション・制約といった保持も可能です。

スクレイピング

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

Python

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

データマイニング

データマイニングは、購買履歴やクレジットカードの利用履歴、電話の通話履歴など企業にある大量のデータを解析して、その中に隠れたパターンやルールを探し出す技術です。DMと略されることもあります。

Q&A

解決済

1回答

2473閲覧

datasetライブラリーを用いたデータの保存が正しくできない

yukawakota

総合スコア14

DataSet

DataSetは、ADO.NETアーキテクチャのコンポーネントです。データベースから取得したレコードをメモリ領域に格納するクラスを指します。データの保持やテーブル間のリレーション・制約といった保持も可能です。

スクレイピング

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

Python

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

データマイニング

データマイニングは、購買履歴やクレジットカードの利用履歴、電話の通話履歴など企業にある大量のデータを解析して、その中に隠れたパターンやルールを探し出す技術です。DMと略されることもあります。

0グッド

0クリップ

投稿2020/02/06 14:58

前提・実現したいこと

Pythonスクレイピングの基本と実践という書籍を使ってWEBスクレイピングの勉強をしています。この中で仮想の書籍販売サイトをスクレイピングし、データをpythonのdatasetライブラリーを用いて保存したいと思っています。

発生している問題

取得したデータをbooks.dbというファイルに保存しました。
しかし、保存したファイルDB Browserを使って見てみると、
books.db
のように、UPC以降のカラムの内容がNULLになってしまっています。

該当のソースコード

python

1''' 2http://books.toscrape.com/から書籍ごとに 3タイトル、表紙画像、価格、在庫の有無、評価、商品の説明、商品その他の情報 4を取得する 5''' 6 7import requests 8import dataset 9import re 10from datetime import datetime 11from bs4 import BeautifulSoup 12from urllib.parse import urljoin, urlparse 13 14db = dataset.connect('sqlite:///books.db') 15base_url = 'http://books.toscrape.com/' 16 17# すべての本をスクレイピングし、URL、タイムスタンプを保存する 18def scrape_books(html_soup, url): 19 for book in html_soup.select('article.product_pod'): 20 # とりあえず書籍のURLのみ保存する 21 book_url = book.find('h3').find('a').get('href') 22 book_url = urljoin(url, book_url) 23 path = urlparse(book_url).path 24 book_id = path.split('/')[2] 25 # upsertはまず更新を試行してから挿入を実行する 26 db['books'].upsert({'book_id' : book_id, 27 'last_seen' : datetime.now() 28 }, ['book_id']) 29 30# それぞれの本をスクレイピングする 31def scrape_book(html_soup, book_id): 32 main = html_soup.find(class_='product_main') 33 book = {} 34 book['book_id'] = book_id 35 book['title'] = main.find('h1').get_text(strip=True) 36 book['price'] = main.find(class_='price_color').get_text(strip=True) 37 book['stock'] = main.find(class_='availability').get_text(strip=True) 38 book['rating'] = ' '.join(main.find(class_='star-rating').get('class')).replace('star-rating', '').strip() 39 book['img'] = html_soup.find(class_='thumbnail').find('img').get('src') 40 desc = html_soup.find(id='product_description') 41 book['description'] = '' 42 if desc: 43 book['description'] = desc.find_next_sibling('p').get_text(strip=True) 44 book_product_table = html_soup.find(text='Product Information').find_next('table') 45 for row in book_product_table.find_all('tr'): 46 header = row.find('th').get_text(strip=True) 47 # ヘッダーをカラムとして使うのでクリーンにして 48 # SGLiteが受け付けられるようにする 49 header = re.sub('[^a-zA-Z]+', '_', header) 50 value = row.find('td').get_text(strip=True) 51 book[header] = value 52 db['book_info'].upsert(book, ['book_id']) 53 54# カタログ内のページをスクレイピングする 55url = base_url 56inp = input('Do you wish to re-scrape the catalogue (y/n)? ') 57while True and inp == 'y': 58 print('Now scraping page: ', url) 59 r = requests.get(url) 60 html_soup = BeautifulSoup(r.text, 'html.parser') 61 scrape_books(html_soup, url) 62 # 次のページはある? 63 next_a = html_soup.select('li.next > a') 64 if not next_a or not next_a[0].get('href'): 65 break 66 url = urljoin(url, next_a[0].get('href')) 67 68# 古いものから順に、書籍ごとにスクレイピングする 69books = db['books'].find(order_by=['last_seen']) 70for book in books: 71 book_id = book['book_id'] 72 book_url = base_url + 'catalogue/{}'.format(book_id) 73 print('Now scraping book: ', book_url) 74 r = requests.get(book_url) 75 r.encoding = 'utf-8' 76 html_soup = BeautifulSoup(r.text, 'html.parser') 77 scrape_book(html_soup, book_id) 78 # 最後に見たタイムスタンプを更新する 79 db['books'].upsert({'book_id' : book_id, 80 'last_seen' : datetime.now()}, 81 ['book_id']) 82

試したこと

コード内で使った、bookディクショナリーの中身を確認すると正しい情報が得られていました。

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

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

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

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

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

meg_

2020/02/08 03:22 編集

datasetモジュールは知らないのですが、保存(更新)処理が上手くいっていないのではないでしょうか? 保存処理はどこ(コードのどの部分)で行っていますか?
guest

回答1

0

ベストアンサー

カラム名が大文字なのが怪しいと思って試してみたら当たりでした。

python

1# それぞれの本をスクレイピングする 2def scrape_book(html_soup, book_id): 3 # 略 4 for row in book_product_table.find_all('tr'): 5 header = row.find('th').get_text(strip=True) 6 # ヘッダーをカラムとして使うのでクリーンにして 7 # SGLiteが受け付けられるようにする 8 header = re.sub('[^a-zA-Z]+', '_', header) 9 value = row.find('td').get_text(strip=True) 10 # キー(カラム名)を小文字にする 11 book[header.lower()] = value 12 db['book_info'].upsert(book, ['book_id']) 13

なんでそうなるのかは分かりません。
それより、toscrape.com なんてサイトがあるんですね。

投稿2020/02/11 00:45

hoshi-takanori

総合スコア7901

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

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

yukawakota

2020/02/11 02:32

ありがとうございます! コードを変更してカラム名を小文字にしたらデータが保存されました。 pandasを使ってcsvファイルに保存など、もう少し使いやすい方法に変更しようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問