山傘のプログラミング勉強日記

プログラミングに関する日記とどうでもよい雑記からなるブログです。

Pythonクローリング&スクレイピング[増補改訂版] ―データ収集・解析のための実践開発ガイドー その6

第3章 ライブラリによる高度なクローロング・スクレイピング

技術評論社のページのスクレイピング

本のURL を取得
from typing import Iterator
import requests
import lxml.html

def main():
  """
  クローラーの結果を出力
  """

  response = requests.get('https://gihyo.jp/dp')
  urls = scrape_list_page(response)
  for url in urls:
    print(url)

  
def scrape_list_page(response: requests.Response) -> Iterator[str]:
  """
  Response から URL を抜き出す
  """
  html = lxml.html.fromstring(response.text)
  html.make_links_absolute(response.url)
  for a in html.cssselect('#listBook > li > a[itemprop="url"]'):
    url = a.get('href')
    yield url


if __name__ == '__main__':
  main()
本の詳細情報を取得
from typing import Iterator
import requests
import lxml.html
import time
import re

def main():
  """
  クローラーの結果を出力
  """
  session = requests.Session() # 複数ページのクロールで負荷を軽減できる
  response = requests.get('https://gihyo.jp/dp')
  urls = scrape_list_page(response)
  for url in urls:
    time.sleep(0.5) # 0.5秒ごとにアクセスする
    response_detail = session.get(url)
    ebook = scrape_detail_page(response_detail)
    
    for key, value in ebook.items():
      print(key, value)
    

  
def scrape_list_page(response: requests.Response) -> Iterator[str]:
  """
  Response から URL を抜き出す
  """
  html = lxml.html.fromstring(response.text)
  html.make_links_absolute(response.url)
  for a in html.cssselect('#listBook > li > a[itemprop="url"]'):
    url = a.get('href')
    yield url


def scrape_detail_page(response: requests.Response) -> dict:
  """
  詳細ページのRequestから電子書籍の情報を取得する
  """
  html = lxml.html.fromstring(response.text)
  ebook = {
    'url': response.url,
    'title': html.cssselect('#bookTitle')[0].text_content(),
    'price': html.cssselect('.buy')[0].text.strip(), # 空白を取り除く
    # リスト内包表記
    'content': [normalize_spaces(h3.text_content()) for h3 in html.cssselect('#content > h3')],
  }
  return ebook

def normalize_spaces(s: str) -> str:
  """
  連続する空白を一つの空白に置き換え、前後の空白を削除して新しい文字列を取得する
  """
  # raw文字列として扱う
  return re.sub(r'\s+', ' ', s).strip()


if __name__ == '__main__':
  main()

本の URL のリストを取得して、さらにその URL にアクセスして電子書籍の詳細な情報を取得します。このときのクローリングはサーバーに負荷を掛ける可能性があるため、適切に設計する必要があります。

MongoDB

リレーショナルデータベースではない、NoSQL 系のデータベースである MongoDB を使います。

Ubuntu 18.04 に MongoDB の最新版を apt インストールする - サーバー構築と設定 ~初心者にも分かりやすく解説~

感想

結構本格的なクローリングになってきていると思いました。クローリングするには対象のページをどうやって情報を抜き出すかを考えるので、HTML や CSS の知識が必要だと思いました。