Python3のスクレイピングツール作成のときに作った関数

はじめに

今回スクレイピングツールが欲しくて初めてプログラムを作成しました。 基礎文法だけ学んでいたPython3で挑戦しましたが、思っていたよりすんなりできました。 とりあえず個人で使う分には困らないレベルになったので、その際に用意した関数を後から見直せるように書いておきます。 もっといい方法があったりすると思いますが、ご自由にお使いください。 エラー処理やロギングなどまだまだ使いこなせていないので、アドバイスがありましたらコメントにお願いします。

入力関係の関数

Yes,Noの標準入力

if文と組み合わせることが多い

def yes_no_input():
    while True:
        choice = input("Please Enter 'yes' or 'no' [y/N]: ").lower().strip()
        if choice in ['y', 'ye', 'yes']:
            return True
        elif choice in ['n', 'no']:
            return False

標準入力のチェック有り

今回は正しいURLを入力させる正規表現にて使用しました。

import re
def input():
    while True:
        input = input('Please Enter: ').strip()

        pattern = re.compile(r'<正規表現でインプット内容の入力チェック>')

        if pattern.match(input):
            return input

HTTPリクエストとHTML解析

HTTPリクエストを送信してHTMLを取得

後述のrequestsモジュールの方が高速で動くしコード的にもスッキリする。

import urllib.request, urllib.error
def get_html_src(url):
    try:
        req = urllib.request.Request(
            url,
            data=None,
            headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2403.130 Safari/537.36'}
        )

        with urllib.request.urlopen(req) as page:
            page_html=""
            for line in page.readlines():
                page_html += line.decode('utf-8')

    except urllib.error.URLError as e:
        sys.exit("Error! : URLエラーによりページソースを取得できません。")
    except urllib.error.HTTPError as e:
        sys.exit("Error! : HTTPエラーによりページソースを取得できません")

    return page_html

HTTPリクエストを送信してHTMLを取得-改

前述のHTMLを取得するより高速に動きました。ソースもスッキリしてこっちの方が好きです。 requestsモジュールが必要です。 uaはユーザエージェントを変数にしています。

import requests
import sys
def get_html_src(url, ua):
    html = requests.get(url, headers={'User-Agent': ua})
    page_html = html.text
    sys.exit('Error! : エラーによりページソースを取得できません。')

    return page_html

HTMLを解析

HTMLを正規表現で検索してgroup(数値)で特定の情報を取得します。 正規表現で解析できるので応用が聞きますが、後述の方法でもre.compileと組み合わせて使用できます。

import re
def get_title(page_html):
# ソースからタイトル取得する関数
    title_pattern = '<title>.*?</title>'
    title = re.search(title_pattern, page_html)
    # 一致した部分からタグの中身を取得する
    dir_name = re.sub(r'<.*?>','', title.group(0))

    return dir_name

HTMLを解析(改)

上述の正規表現よりもこちらの方が高速で動作しました。 タグを指定して取得しているので、コードから何を取得しているのか分かりやすい。(idだけだと分かりづらいですが。) replaceは”/”が入るとコマンド実行時に区切り文字になるので、変更しています。

from bs4 import BeautifulSoup
def get_title(cls, page_html): 
    soup = BeautifulSoup(page_html, "lxml")
    title = soup.find(id='gj').string.replace('/', '-')
    if title == None:
        soup = BeautifulSoup(page_html, "lxml")
        title = soup.find(id='gn').string.replace('/', '-')

    return title

URLパース

今回は”/”間を取得する必要があったので使用しました。他にも?以降など色々知っておくと便利。 なお、アルゴリズムを見直して使用しなくなった模様。

from urllib.parse import urlparse
def get_url_info(page_url):
    url_path = urllib.parse.urlsplit(page_url).path.split('/')
    url_info = url_path[2]

    return url_info

Linux操作

ディレクトリの作成

os標準のmkdirコマンドをPythonで実現します。

import os
def make_dir():
    if os.path.exists('download'):
        pass
    else:
        os.mkdir('download')
        print('downloadディレクトリを作成しました。')

特にif文を使わなくてもディレクトリの存在チェックも可能です。

import os
def make_dir():
    os.makedirs(save_dir, exist_ok=True)

ファイルの削除

処理完了時に不要なファイルを削除する時に使います。

import os
def remove_file(file_name)
    if os.path.isfile('file_name'):
        os.remove('file_name')

ファイルの行数指定の読み込み

ファイルを行数指定して読み込むことができる。 今回の用途では前回の中断処理を中間ファイルの最終行から読み込む方法で使用した。 最後にキャッシュクリアを忘れないように。 1行づつ読み込む時はreadlineを使う。

import linecache
lineinfo = linecache.getline('finish_url.list', <行数>)
linecache.clearcache()

便利ツール

プログレスバーを表示させるツール

今回は複数の画像を取得するので、進捗がわかるように導入した。 カウントを表示させるのも有りかもしれないが、プログレスバー1行の方がスマートに見える。

from tqdm import tqdm
with tqdm(total=100) as pbar:
    for in range(100)
        pbar.update(1)

終わりに

今回のツール作成で得た知見を全ては書ききれていません。 f.openみたいな書き方はやめてwith opent('','r') as fみたいな書き方を使うようになったりとか。 PEP8に沿って書くことは意識しましたが、まだまだです。 やはりプログラミングは実際に書いてみないとわからなかったり、アルゴリズムだけでなく細かい書き方や使用するライブラリによっても速度が変わるので勉強しがいがあります。