[Python3] Python3でスクレイピングしてみた

Python

ちょっとPythonを使うことがあったのでメモ。

なかなかクソなwebアプリからログを取りたいのだがcsv出力の機能がなかったのでスクレイピングで拾ってきました。

存在以上のページを指定すると404が出るわけではないので(文字化けしてページが永遠に作成される)、どこかに書いてある最大ログ数を取って来てループを回しています。(次へが押せなくなるとかもない)

HTMLタグにidとかclassがついていれば”Beautiful Soup”というモジュールを使えば10行くらいで完成するのですが、一つもタグになかったのでXPathを使って指定しています。

また、ブラウザでXPathをコピーするとTBodyタグが抽出出来たのですが実際のソースには無かったみたで、めちゃくちゃハマりました。(ブラウザが補完している模様)

正規表現を使うためだけに”re”をimportしたり、モジュールを使いまくる感じでした。

初めてPythonを触ったのでぐちゃぐちゃなコードですが。。。

import requests
import lxml.html
import re
from time import sleep
from datetime import datetime,timedelta
import os

# クラス宣言の時には引数にobjectが入るのがトレンド
class Logger(object):
    ''' クラス変数で使うならこっち
    counter = 0
    end = ''
    flag = True
    done = False
    # w:上書き r:追記
    filePath = "XXXX.txt"
    '''

    # インスタンス変数
    def __init__(self,counter,end,flag,done,filePath):
        self.counter = counter
        self.end = end
        self.flag = flag
        self.done = done
        self.filePath = filePath

    # 自作関数の宣言時引数にselfが必要
    def putLog(self):
        # withで自動でストリーム閉じる(C#でいうusing)
        with open(self.filePath, 'a') as file:    
            while self.flag:
                # format関数を使って文字列の{}に値を埋め込む
                uri = 'http://XXXX/log_page&page={}'.format(self.counter)
                # Basic認証対策
                res = requests.get(uri,auth=('userID','Password'))
                # アクセス出来た時のみ
                if res.status_code == 200:
                    html = res.text
                    root = lxml.html.fromstring(html)
                    # XPathでピンポイントで取得する
                    targets = root.xpath("/html/body/font/table/tr[5]/td/table/tbody/tr")
                    
                    if self.counter == 0:
                        # 1ページ目でMaxレコードの数字拾う
                        fin = root.xpath("/html/body/font/table/tr[5]/td/table/tbody/tr[24]/td[1]")
                        s = str(fin[0].text_content())
                        self.end = re.search(r'([0-9]+)',s).group()

                    # 1ページのログをひたすらスクレイピング
                    for c in range(2,len(targets) - 3 ):
                        day = root.xpath("/html/body/font/table/tr[5]/td/table/tbody/tr[{}]/td[4]".format(c + 1))[0].text_content()
                        time = root.xpath("/html/body/font/table/tr[5]/td/table/tbody/tr[{}]/td[5]".format(c + 1))[0].text_content()
                        userid = root.xpath("/html/body/font/table/tr[5]/td/table/tbody/tr[{}]/td[2]".format(c + 1))[0].text_content()
                        name = root.xpath("/html/body/font/table/tr[5]/td/table/tbody/tr[{}]/td[3]".format(c + 1))[0].text_content()
                        # 謎にmm/dd/YYYY形式なので変換
                        dayTime = day[6:10] + '/' + day[0:5] + ' ' + time
                        baseDay = day[6:10] + '/' + day[0:5]
                        # 日付型で比較するとき用
                        #dt = datetime.strptime(baseDay, '%Y/%m/%d')
                        # 取って来た日の前日を取得
                        yesterday = datetime.today() - timedelta(days=1)
                        yesterday = datetime.strftime(yesterday, '%Y/%m/%d')
                        
                        # 取って来た日付が昨日なら書く
                        if baseDay == yesterday:
                            file.write(dayTime + ' ' + userid + ' ' + name + '\n')
                            
                            if str(targets[c].text_content()).find(self.end) != -1:
                                self.flag = False
                                break
                        elif baseDay < yesterday:
                            # 昨日分を書き終わり一昨日になったら処理終了
                            self.flag = False
                            break                    
                else:
                    break
                
                if self.flag:
                    self.counter += 1
                    sleep(1)
                else:
                    break

# インスタンス化
log = Logger(0, '', True, False, "XXXXX.txt")
# オブジェクトの関数使用
log.putLog()

おまけ

コマンドライン引数の使い方

import sys

# コマンドライン引数取得(0番目にはこのpyファイルのパスが入っている)
args = sys.argv

実行する時にファイル名の後ろに文字列をいれますが、Pythonでは0番目にファイル名が自動で入ります
なので文字列の最初はargs[1]なんです。

おもしろい!

ご指摘や改善点ありましたらどんどんコメントください

コメント

タイトルとURLをコピーしました