宇和島市プレミアム付商品券が使えるお店をスクレイピング

!wget https://www.city.uwajima.ehime.jp/uploaded/attachment/24937.pdf -O list.pdf
!wget https://www-eu.apache.org/dist/pdfbox/2.0.17/pdfbox-app-2.0.17.jar -O pdfbox-app.jar

!java -jar pdfbox-app.jar ExtractText -startPage 2 -sort -encoding UTF-8 list.pdf
import csv
import re


reg1 = re.compile(r"^(.+)\s(宇和島市.+)\s((089|070|080|090|0120)(.+))$")
reg2 = re.compile(r"^(.+)\s(宇和島市.+)$")

with open("result.tsv", "w", encoding="utf-8") as fw:
    writer = csv.writer(fw, dialect=csv.excel_tab, lineterminator="\n")

    with open("list.txt", mode="rt", encoding="utf-8") as fr:

        genre = ""

        # ヘッダー
        rowpre = ["業種", "店舗名", "住所", "電話番号"]

        for line in fr:

            line = line.rstrip()

            # 除外行
            if line.endswith(("取扱店一覧", "現在", "電話番号", "ページ")):
                continue

            # 業種
            if line.startswith("【") and line.endswith("】"):
                genre = line.strip("【】")
                continue

            # print(rowpre)
            # print(genre, line)

            # 電話番号あり
            m1 = reg1.search(line)

            if m1:
                data = [(m1.group(i).strip()) for i in range(1, 4)]

                row = [genre] + data

                writer.writerow(rowpre)

                rowpre = row

            else:

                # 電話番号なし
                m2 = reg2.search(line)

                if m2:
                    data = [(m2.group(i).strip()) for i in range(1, 3)]

                    # 電話番号に空白
                    row = [genre] + data + [""]

                    writer.writerow(rowpre)

                    rowpre = row

                else:
                    data = re.split(r"\s{2,}", line.strip(), 1)

                    n = len(data)

                    rowpre[1] += " " + data[0]

                    if n == 2:
                        rowpre[2] += " " + data[1]

            # 括弧前スペースを除去
            rowpre[1] = rowpre[1].replace(" (", "(")
            rowpre[2] = rowpre[2].replace(" (", "(")

        else:
            writer.writerow(rowpre)

松山市プレミアム付商品券が使えるお店をスクレイピング

premium-gift.jp

import csv
import time
import urllib.parse

import requests
from bs4 import BeautifulSoup

url = 'https://premium-gift.jp/matsuyama/use_store'

headers = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
}

s = requests.Session()

with open('result.csv', 'w') as fw:
    writer = csv.writer(fw, dialect='excel', lineterminator='\n')

    # ヘッダー登録
    writer.writerow(["ID", "業種", "店舗名", "郵便番号", "所在地", "電話番号", "URL"])

    for n in range(1, 90):

        params = {
            "events": "page",
            "id": n,
            "store": "",
            "addr": "",
            "industry": ""
        }

        r = s.get(url, headers=headers, params=params)

        print(r.url)

        if r.status_code == requests.codes.ok:

            soup = BeautifulSoup(r.content, 'html5lib')

            for i in soup.select("div.store-card__item"):

                # 店舗名を取得
                title = i.select_one("h3.store-card__title").get_text(
                    strip=True)

                # 業種を取得
                tag = i.select_one("p.store-card__tag").get_text(strip=True)

                # 郵便番号・住所・電話番号・URLを取得
                temp, tel, link = [
                    td.get_text(strip=True) for td in i.select(
                        "table.store-card__table > tbody > tr > td")
                ]

                # 郵便番号と住所を分離
                postal, *address = temp.split()

                # IDのみ抽出
                id = urllib.parse.parse_qs(
                    urllib.parse.urlparse(
                        i.select_one("a.store-card__button").get(
                            "href")).query)["id"][0]

                data = [id, tag, title, postal, ' '.join(address), tel, link]

                writer.writerow(data)

            time.sleep(1)

新居浜市プレミアム付商品券が使えるお店をスクレイピング

niihama-premium.com

import requests
import csv
from bs4 import BeautifulSoup

url = "https://niihama-premium.com/citizen/shop.html"

headers = {
    "User-Agent":
    "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
}

r = requests.get(url, headers=headers)

if r.status_code == requests.codes.ok:

    soup = BeautifulSoup(r.content, "html5lib")

    with open("result.csv", "w") as fw:
        writer = csv.writer(fw, dialect="excel", lineterminator="\n")
        writer.writerow(["業種", "店舗名", "住所", "TEL", "備考"])

        for i in soup.select("#shop01 > div > section"):

            # 業種取得
            genre = i.select_one("h4 > span").get_text(strip=True)

            for tr in i.select("div.list_area > table.shop_list > tbody > tr"):

                # tdがあるか
                if tr.td:
                    data = [td.get_text(strip=True) for td in tr.select("td")]

                    writer.writerow([genre] + data)

「Windows 10 May 2019 Update」と一部NEC製PCの間に非互換性問題

forest.watch.impress.co.jp

今頃かよ公開後3日間ぐらい再インストールしたり設定いろいろ試行錯誤してだめだったので下のWi-Fiに交換して正解やったみたいやね。スピード早くなるし前より安定しているみたいやから

imabari.hateblo.jp

キャッシュレス・消費者還元事業事務局審査を通過した加盟店一覧をPDFをCSV変換4

Colaboratoryで公開

PDFダウンロードからTSV変換まで

colab.research.google.com

# -*- coding: utf-8 -*-

import pandas as pd
from tabula import read_pdf

# ページ数入力
max_page = 6360

pages = f"3-{max_page}"

df = read_pdf("kameiten_touroku_list.pdf",
              lattice=True,
              pages=pages,
              java_options=["-Xmx2G"],
              pandas_options={
                  "names":
                  ["No.", "都道府県", "市区町村", "事業所名(屋号)", "業種", "区分", "還元率"]
              })

print(df)

# データの前処理

# 表タイトル除去
df = df[df["No."] != "No."]

# データの整形

# グループ別に分ける
grouped_df = df.groupby((df["No."] == '1').cumsum())

# 固定店舗(EC・通信販売を除く)
df1 = grouped_df.get_group(1).copy()

df1.drop(columns="No.", inplace=True)

# インデックスをリセット
df1.reset_index(inplace=True, drop=True)
df1.index += 1

print(df1)

# EC・通信販売(楽天市場)
df2 = grouped_df.get_group(2).copy()

df2.drop(columns=["No.", "事業所名(屋号)", "業種", "区分", "還元率"], inplace=True)
df2.rename(columns={"都道府県": "事業所名(屋号)", "市区町村": "還元率"}, inplace=True)

# 業種・区分を登録
df2["業種"] = "EC・通信販売"
df2["区分"] = "楽天市場"

# インデックスをリセット
df2.reset_index(inplace=True, drop=True)
df2.index += 1

print(df2)

# EC・通信販売(Yahoo!ショッピング)
df3 = grouped_df.get_group(3).copy()

df3.drop(columns=["No.", "事業所名(屋号)", "業種", "区分", "還元率"], inplace=True)
df3.rename(columns={"都道府県": "事業所名(屋号)", "市区町村": "還元率"}, inplace=True)

# 業種・区分を登録
df3["業種"] = "EC・通信販売"
df3["区分"] = "Yahoo!ショッピング"

# インデックスをリセット
df3.reset_index(inplace=True, drop=True)
df3.index += 1

print(df3)

# EC・通信販売(その他ECサイト)
df4 = grouped_df.get_group(4).copy()

df4.drop(columns=["No.", "事業所名(屋号)", "業種", "区分", "還元率"], inplace=True)
df4.rename(columns={"都道府県": "事業所名(屋号)", "市区町村": "還元率"}, inplace=True)

# 業種・区分を登録
df4["業種"] = "EC・通信販売"
df4["区分"] = "その他ECサイト"

# インデックスをリセット
df4.reset_index(inplace=True, drop=True)
df4.index += 1

print(df4)

# データを連結
df_all = pd.concat([df1, df2, df3, df4], sort=False)

# 還元率の%を除去
df_all["還元率"] = df_all["還元率"].str.rstrip("%").astype(float)

print(df_all)

# TSVファイルに保存
df_all.to_csv('kameiten_touroku_list.tsv', sep='\t')

キャッシュレス・消費者還元事業事務局審査を通過した加盟店一覧をPDFをCSV変換3

www.meti.go.jp

セルが「縮小して全体を表示」に変更されたのかセル内に縮小表示されたのでtabulaで抽出できるようになりました

github.com

tabula-1.0.3-jar-with-dependencies.jarをダウンロード

-Xmx1G オプションでメモリを増やせば動きました

java -jar -Xmx1G tabula-1.0.3-jar-with-dependencies.jar -o list.tsv -l -p 3-6360 kameiten_touroku_list.pdf

全ページではエラーになるため200ページごとに分割して実行

import shlex
import subprocess

start_page = 3
end_page = 6360

previ = start_page

while True:

    i = previ + 200

    i -= i % 200

    i = i if i < end_page else end_page

    command = f'java -jar tabula-1.0.3-jar-with-dependencies.jar -f TSV -o {previ:0}-{i:0}.tsv -l -p {previ:0}-{i:0} kameiten_touroku_list.pdf'

    p = subprocess.Popen(shlex.split(command))

    p.wait()

    if i < end_page:
        previ = i + 1
    else:
        break