前提・実現したいこと
Pythonスクレイピングの基本と実践という書籍を使ってWEBスクレイピングの勉強をしています。この中で仮想の書籍販売サイトをスクレイピングし、データをpythonのdatasetライブラリーを用いて保存したいと思っています。
発生している問題
取得したデータをbooks.dbというファイルに保存しました。
しかし、保存したファイルDB Browserを使って見てみると、
のように、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ディクショナリーの中身を確認すると正しい情報が得られていました。
回答1件
あなたの回答
tips
プレビュー