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

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

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

第5章 クローリング・スクレイピングの実践とデータの活用

オープンデータ

政府や自治体や企業が持つデータを公開し、自由に利用してもらう仕組みであるオープンデータを用いてスクレイピングを行います。

新幹線における旅客輸送量

新幹線旅客輸送量の推移を見ます。

統計情報 - 国土交通省

PDF ファイルに対応するために、PDFMiner というライブラリを使います。

pip install pdfminer.six chardet

PDF ファイル内のテキストをグループ化します。

import sys
from typing import List
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox, LTComponent
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage


def main():
    """
    PDF ファイルからテキストボックスを抽出して表示
    """
    laparams = LAParams(detect_vertical=True)
    resource_manager = PDFResourceManager()
    device = PDFPageAggregator(resource_manager, laparams=laparams)
    interpreter = PDFPageInterpreter(resource_manager, device)
    
    with open(sys.argv[1], 'rb') as f:
        for page in PDFPage.get_pages(f):
            interpreter.process_page(page)
            layout = device.get_result()
            boxes = find_textboxes_recursively(layout)
            boxes.sort(key=lambda b: (-b.y1, b.x0))

            for box in boxes:
                print('-' * 10)
                print(box.get_text().strip())

def find_textboxes_recursively(component: LTComponent) -> List[LTTextBox]:
    """
    再帰的にテキストボックスをリストに入れる
    """
    if isinstance(component, LTTextBox):
        return [component]
    
    if isinstance(component, LTContainer):
        boxes = []
        for child in component:
            boxes.extend(find_textboxes_recursively(child))
        return boxes
    return []


if __name__=='__main__':
    main()

日本の美術館の URI と住所

DBpedia Japanese

Linled Data というデータ構造は RDF で記述され、SPARQL というクエリ言語を使ってデータを検索します。

from SPARQLWrapper import SPARQLWrapper

sparql = SPARQLWrapper('http://ja.dbpedia.org/sparql')

sparql.setQuery(r"""
SELECT * WHERE {
    ?s rdf:type dbpedia-owl:Museum ;
        prop-ja:所在地 ?address .
    FILTER REGEX(?address, "^\\p{Han}{2,3}[都道府県]")
} ORDER BY ?s
""")
sparql.setReturnFormat('json')
response = sparql.query().convert()

for result in response['results']['bindings']:
    print(result['s']['value'], result['address']['value'])

感想

Web 上でクエリの処理を行ってデータの提供を行うという仕組みがあると知りました。SPARQL を使えるようにすることでデータの取得方法の幅が広がると思います。