質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

Q&A

1回答

3039閲覧

pythonであるサーバから自分のcentOSサーバのmysqlデータベースに自動で更新していくコードを作りたい。

HidenoriYamano

総合スコア60

CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

0グッド

3クリップ

投稿2015/06/19 01:07

プログラミング初心者のため、あまり詳しくないので、易しく解説していただけると嬉しいです。研究室で、下図のような環境を構築したいと考えています。つまり、元サーバのそれぞれのtree構造の一番下にあるtxtデータのうち、取得日と同じ日付のファイルを取得し、研究室のサーバのmysqlのテーブルに入れる環境を作りたいです。そもそも、可能でしょうか。また、将来的に、統計的な解析やグラフの記述をしていくことも踏まえて、言語は、pythonで統一しようと思っています。参考となるコードを教えていただけると嬉しいです。ちなみに学内のパソコンから外部のサーバにアクセスする際は、proxy環境をくぐらないといけませんので、そこもどう対処すればいいか教えていただけると嬉しいです。
![![イメージ説明]WIDTH:600]WIDTH:600

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lib

2015/06/19 23:57

細かいですが、気になった点をいくつか ・学内と学外の区別がわかりません。 ・作ったものを配置する先はどちらなのか。(元サーバーなのか、研究室サーバーなのか) 推測で後者だとは思いますが。 ・元サーバーにwebサーバーの設置は可能なのか、もしくはアクセスができるようになっているのか。 ・ネットの環境が図に現れていません。まずは以下のような形からはいってみてはいかがでしょうか。 http://hesonogoma.com/visio/networkdiagram.html ・そもそも研究室内の話なので、そこの中で解決できませんか?(理由は秘密保持なんちゃら)
HidenoriYamano

2015/06/20 01:51

元サーバが学外、研究室サーバが学内です。・研究室サーバに作ったものを配置します。・元サーバにはwebサーバ設置可能です。・データは秘密事項なのですが、なにせ、自分達の研究チームに、こういったインフラに詳しい者がいないため、なにか、ヒントになることはと思い、質問させていただきました><
guest

回答1

0

お邪魔します。

ご質問の内容は噛み砕くと以下の4点であっていますか?
0. pythonを使ってファイル名に特定の文字列を含むテキストファイルを取得
0. ファイルの内容を読み込む
0. データベースにファイルの内容を書き出す
0. データベースはプロキシ経由で別サーバにあるため、これとのコネクションの確立
まず、1からですが、pythonのosモジュールにwalkというディレクトリの内容を再帰的に辿って調べてくれる関数があるので、これを使います。
また、環境がよくわからないのでこれは経験とか感の領域ですが、対象のファイルを一旦収集して手元にコピーすることにします。

lang

1import re 2from tempfile import mkdtemp 3from shutil import copyfile 4from os import walk 5 6FILENAME_PATTERN = '20150601' 7ROOT_PATH = r'C:\\Documents and Settings\\' 8 9r = re.compile("[a-zA-Z]+-(?P<date>\d{8})") 10 11def collect(filename): 12 tempdir = mkdtemp() 13 copyfile(filename, tempdir) 14 return os.path.join(tempdir, os.path.basename(filename)) 15 16def gen_filelist(path): 17 for root, dirs, files in os.walk(path): 18 for file in files: 19 m = r.match(file) 20 if(m or FILENAME_PATTERN in m.groupdict().values()): 21 # ファイルを何かが開いていたら厄介なので、一旦テンポラリにコピーする 22 yield collect(os.path.join(root, file)) 23

2.のファイルの内容を読み込む、ですが、open関数というのが標準ライブラリにあるのでこれでファイルを開いて内容を読み込みます。

lang

1def read_line(data): 2 #データを読み出す。例えばcsvファイルをカンマで分けるとか。今回は何もせずそのまま返します。 3 return data 4 5def read(filename): 6 with open(filename, "r") as f: 7 lines = [] 8 for line in f.readlines(): 9 lines.append(read_line(line)) 10 return lines

3.のデータベースにファイルの内容を書き出す、ですが、単純にやるよりは将来のデータ構造の変化を考慮してORMを使うのが良いと思います。SQLAlchemyを使ってみます。(データの取得時にも、ここで定義したテーブルアクセサは使うことができますしね。)
ORMをセットアップしてテーブルにデータを登録するには以下のようにします。
テーブルの構造とか適当ですので読み替えてください。
(既存のテーブルにORMをアタッチさせる場合、他に少し工夫がいるかもしれません。)

lang

1from sqlalchemy import create_engine 2from sqlalchemy.orm import sessionmaker 3from sqlalchemy.ext.declarative import declarative_base 4from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, Sequence 5 6Base = declarative_base() 7 8class Data(Base): 9 __tablename__ = 'tablename' 10 id = Column('id', Integer, Sequence('id_seq'), primary_key=True) 11 somedata = Column('somedata', String(512)) 12 13 def __init__(self, somedata): 14 self.somedata = somedata 15 def __repr__(self): 16 return "<Data('%s',...)>" % (self.somedata) 17 18def main(): 19 #ORMのセットアップ 20 engine = create_engine('mysql://<ユーザ名>:<パスワード>@<ip>/<db名>', encoding='utf-8', echo=True) 21 Session = sessionmaker(bind=engine) 22 session = Session() 23 data = Data("データの内容。。。。。") 24 #DBに対して書き込みを行う。 25 session.add(data) 26 session.commit()

4.のプロキシ越えの件ですが、基本的にはDBのクライアントソフトウェアで接続できるなら問題ないはずです。問題がある場合は、クライアントソフトウェアでも接続できないはずです。
(セッションを維持できない可能性があります。そういった問題が発生するのであれば、プロキシの設定を適時変更するなどしてください。プロキシの設定を変更できない場合、ポートフォワーディングを行うとか、何らかのプロトコルによるトンネリングを試みたりする余地はあるとは思いますが、大変そうです。どちらにしてもDBサーバと双方に何か仕込む必要がありますね。)

まとめ

提示したソースをつながるように一部改変したものを載せておきます。
一切テストをしていないので、問題があったら教えてください。w
なお、提示したソースの動作にはSQLAlchemyとMySQLに接続するためのpython用ドライバが必要です。
[MySQL用のドライバのうち一般的なもの]
・MySQL-python
・PyMySQL
・mysql-connector-python
適当に入れてください。

lang

1# -*- coding: utf-8 -*- 2 3import re 4import os 5from tempfile import mkdtemp 6from shutil import copyfile 7from os import walk 8 9from sqlalchemy import create_engine 10from sqlalchemy.orm import sessionmaker 11from sqlalchemy.ext.declarative import declarative_base 12from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, Sequence 13 14 15FILENAME_PATTERN = '20150601' #収集対象とするファイル名のパターン 16ROOT_PATH = r'C:\\Documents and Settings\\' #収集するファイルが存在するトップディレクトリ 17CONNECT_STRING = 'mysql://<ユーザ名>:<パスワード>@<ip>/<db名>' #DB接続文字列 18 19r = re.compile("[a-zA-Z]+-(?P<date>\d{8})\.txt") #対象ファイル名を示す正規表現を定義。 20 21Base = declarative_base() 22 23class Data(Base): 24 __tablename__ = 'tablename' 25 id = Column('id', Integer, Sequence('id_seq'), primary_key=True) 26 somedata = Column('somedata', String(512)) 27 28 def __init__(self, somedata): 29 self.somedata = somedata 30 def __repr__(self): 31 return "<Data('%s',...)>" % (self.somedata) 32 33 34 35def collect(filename): 36 tempdir = mkdtemp() 37 copyfile(filename, tempdir) 38 return os.path.join(tempdir, os.path.basename(filename)) 39 40def gen_filelist(path): 41 for root, dirs, files in os.walk(path): 42 for file in files: 43 m = r.match(file) 44 if(m and FILENAME_PATTERN in m.groupdict().values()): 45 # ファイルを何かが開いていたら厄介なので、一旦テンポラリにコピーする 46 yield collect(os.path.join(root, file)) 47 48def read_line(data): 49 #データを読み出す。例えばcsvファイルをカンマで分けるとか。 50 #今回は、ORMのクラスにデータを格納してそのまま返します。 51 return Data(data) 52 53def read(filename): 54 with open(filename, "r") as f: 55 lines = [] 56 for line in f.readlines(): 57 lines.append(read_line(line)) 58 return lines 59 60 61def main(): 62 #SQLAlchemyの準備 63 engine = create_engine(CONNECT_STRING, encoding='utf-8', echo=True) 64 Session = sessionmaker(bind=engine) 65 session = Session() 66 67 #ファイルの一覧を取得 68 files = gen_filelist(ROOT_PATH) 69 70 #ファイルの内容を取得 71 for file in files: 72 data = read(file) 73 session.add(data) 74 75 #データベースへ内容を登録 76 session.commit() 77 78if __name__ == '__main__': 79 main()

(2015/06/28追記)

ssh(sftp)経由でリモートのパスを舐め、ファイルを取得してくるように改変します。
その前に、サードパーティのモジュールをインストールします。

lang

1pip install paramiko

※paramikoのインストールには色々と厄介なことがあるようです。linuxでは起こりにくいとは思いますが、ハッシュ化や暗号化モジュールがうまく入らない場合、また情報をください。

sshでファイルを収集するプログラムは次のような感じでできます。
ssh経由でファイルを探す部分は手作りですね。walkを適当に拾ったのを参考に自作しました。(黒)
1件だけ懸念点があり、SHHで接続に失敗する場合、直接鍵ファイルを指定する必要があるかもしれません。

コメントにしている、以下のコードを有効にし、鍵ファイルへのパスを直接指定してください。
conn.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))

以下、対象ホストSSH接続し、ファイルを収集、内容をデータベースに書き出すサンプルです。
データベースのテーブル定義などは考慮していません。適時修正ください。

lang

1# -*- coding: utf-8 -*- 2 3import re 4import os 5from tempfile import mkdtemp 6 7import paramiko 8from stat import S_ISDIR 9 10from sqlalchemy import create_engine 11from sqlalchemy.orm import sessionmaker 12from sqlalchemy.ext.declarative import declarative_base 13from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, Sequence 14 15HOST_ADDRESS = "XX.XX.XX.XX" #データ収集時の接続先ホストIPアドレス 16SSH_PORT = 22 #SSH接続ポート 17SSH_PASSWORD = "XXXXXXXX" #SSH接続パスワード 18SSH_USERNAME = "wheeluser" #SHH接続ユーザ名 19 20FILENAME_PATTERN = '20150601' #収集対象とするファイル名のパターン 21ROOT_PATH = r'/home/username/' #収集するファイルが存在するトップディレクトリ 22CONNECT_STRING = 'mysql://<ユーザ名>:<パスワード>@<ip>/<db名>' #DB接続文字列 23 24# ローカルがwindows機である場合、os.path.joinのパスのデリミタで問題がでるのでその対処 25RELATIONSHIP_TO_HOST = "posix_to_posix" # "posix_to_posix" / "nt_to_posix" / "posix_to_nt" 26 27if RELATIONSHIP_TO_HOST == "posix_to_posix": 28 from os import path as remote_path 29elif RELATIONSHIP_TO_HOST == "nt_to_posix": 30 import posixpath as remote_path 31elif RELATIONSHIP_TO_HOST == "posix_to_nt": 32 import ntpath as remote_path 33 34import logging 35from datetime import datetime 36logging.basicConfig(filename=datetime.today().strftime(r"%Y%m%d_%H%M%S")+'.log', level=logging.DEBUG) 37 38r = re.compile("[a-zA-Z]+-(?P<date>\d{8})\.txt") #対象ファイル名を示す正規表現を定義。 39 40Base = declarative_base() 41 42class Data(Base): 43 __tablename__ = 'tablename' 44 id = Column('id', Integer, Sequence('id_seq'), primary_key=True) 45 somedata = Column('somedata', String(512)) 46 47 def __init__(self, somedata): 48 self.somedata = somedata 49 def __repr__(self): 50 return "<Data('%s',...)>" % (self.somedata) 51 52 53def walk(sftp, path): 54 current = path 55 files = [] 56 folders = [] 57 for item in sftp.listdir_attr(current): 58 if S_ISDIR(item.st_mode): 59 folders.append(item.filename) 60 else: 61 files.append(item.filename) 62 yield current, folders, files 63 for folder in folders: 64 for x in walk(sftp, remote_path.join(path, folder)): 65 yield x 66 67def collect(sftp, filename): 68 tempdir = mkdtemp() 69 dist = os.path.join(tempdir, os.path.basename(filename)) 70 logging.info("copy file from " + filename + " to " + dist) 71 sftp.get(filename, dist, lambda x, y: (logging.warning("File tranceport fail !!!") if x!=y else logging.info("File tranceport success."))) 72 return dist 73 74def gen_filelist(sftp, path): 75 for root, dirs, files in walk(sftp, path): 76 for file in files: 77 m = r.match(file) 78 if(m and FILENAME_PATTERN in m.groupdict().values()): 79 # ファイルを何かが開いていたら厄介なので、一旦テンポラリにコピーする 80 yield collect(sftp, remote_path.join(root, file)) 81 82def read_line(data): 83 #データを読み出す。例えばcsvファイルをカンマで分けるとか。 84 #今回は、ORMのクラスにデータを格納してそのまま返します。 85 return Data(data) 86 87def read(filename): 88 with open(filename, "r") as f: 89 lines = [] 90 for line in f.readlines(): 91 if(line.strip() != ""): 92 lines.append(read_line(line)) 93 return lines 94 95 96def main(): 97 #SQLAlchemyの準備 98 engine = create_engine(CONNECT_STRING, encoding='utf-8', echo=True) 99 Session = sessionmaker(bind=engine) 100 session = Session() 101 102 #SFTP接続の準備 103 conn = paramiko.SSHClient() 104 conn.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 105 #conn.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) #鍵ファイルを直接指定する場合 106 conn.connect(HOST_ADDRESS, port=SSH_PORT, password=SSH_PASSWORD, username=SSH_USERNAME) 107 sftp = conn.open_sftp() 108 109 #ファイルの一覧を取得 110 files = gen_filelist(sftp, ROOT_PATH) 111 112 #ファイルの内容を取得 113 for file in files: 114 data = read(file) 115 session.add(data) 116 117 #データベースへ内容を登録 118 session.commit() 119 120if __name__ == '__main__': 121 main()

投稿2015/06/20 20:27

編集2015/07/01 08:11
ShinpeiYamamoto

総合スコア540

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HidenoriYamano

2015/06/22 07:09

ご回答ありがとうございます。質問が良くなかったので訂正させてください。 >>4. データベースはプロキシ経由で別サーバにあるため、これとのコネクションの確立 データベースは、研究室内のローカルネットワークにあるため、プロキシは不要です。ですが、元データのサーバが、外部にあるため、そこに、接続してデータを取得するために、プロキシ設定が必要なのかと思います。
HidenoriYamano

2015/06/22 07:22

やりたいこととしては、ご回答者様の考え方で、基本的にはあっていますが、一応、私の方で見解をまとめますと、 1. 外部サーバにssh接続 2. 指定の日付(取得日)のファイルを取得 3. ファイルを開き、内容を取得 4. データベースのテーブル内に、適切な箇所にデータを挿入 1〜4を毎日、自動で行ってくれる。 これが、理想型です。自動化するコードなどありましたらそちらも教えていただきたいです><
HidenoriYamano

2015/06/22 07:33

何度もすいません。上記の1. の際に、秘密鍵の認証というのが必要です。こちらに関しては、別に質問しているのですが、まだ解決していません。 https://teratail.com/questions/11630
ShinpeiYamamoto

2015/06/24 19:56 編集

遅くなって申し訳ないです。外部サーバ上のディレクトリからファイルを取得する必要があるのですね。外部サーバにssh接続するのであれば、paramikoを使うと良いと思います。 ちょっと動かしてから投稿したいので週末にでも回答のソースに追記しておきますが、それでは間に合わないかもしれないので、リンクを張っておきます。(基本的には、提示したソースのうちファイル探索とコピーをssh経由(sftp)で行えばよいだけですね。ほんの少し変更するだけで大丈夫だと思います。悩むとしたらディレクトリを舐める部分を自分で実装しないといけなさそうなところですが、str(SSHClient.lstat())がd始まりかどうかとかでディレクトリか否か判断する ー ls -lhdと一緒ですね ーとできそうかなと思います。) paramiko http://paramiko-docs.readthedocs.org/en/latest/api/client.html paramiko wrapper(sftp_walk) https://gist.github.com/johnfink8/2190472 SFTP で任意のディレクトリ以下のリモートファイルをコピーする http://atasatamatara.hatenablog.jp/entry/20120814/1344940445
ShinpeiYamamoto

2015/06/28 12:05

お邪魔します。ひとつコメント欄の中で「毎日、自動で行ってくれる」というのを読み飛ばしていました。スクリプト中のFILENAME_PATTERNという定数に収集対象のファイルを指定するパターンを設定しています。 スクリプトを動作させるサーバの時計が合っているなら、 FILENAME_PATTERN=datetime.today().strftime(r"%Y%m%d") に置き換えればよいですね。(loggingを初期化しているコードより後でやってください。) あとはcronで毎日定期実行すれば勝手にやってくれるでしょう。 テーブルに登録するところだけ実際の環境に合わせて調整が必要でしょうが。
HidenoriYamano

2015/06/28 17:00

ありがとうございます。自分の環境でうまくか今週試してみたいと思います。また、質問するかもしれませんがよろしくお願いします。
HidenoriYamano

2015/06/29 07:52

作っていただいたスクリプトで、step1のみ実行してみたのですが rbenv: no such command `init' File "/Applications/Python 2.7/program/pythontest/test1.py", line 25 yleid collect(os.path.join(root, file)) ^ SyntaxError: invalid syntax とエラーが出ます。なぜでしょうか。
ShinpeiYamamoto

2015/07/01 08:09 編集

スペルミスです;ごめんなさい。追記していった後のほうでは直ってますね。yield collect(os.path.join(root, file))ですね。
HidenoriYamano

2015/07/06 05:20

ありがとうございます。また、つまずいたので質問させてください。 def collect(filename): tempdir = mkdtemp() copyfile(filename, tempdir) return os.path.join(tempdir, os.path.basename(filename)) この部分のcopyfileのところで以下のようにエラーが出ます。 Traceback (most recent call last): File "/Applications/Python 2.7/program/pythontest/text_test.py", line 57, in <module> print collect("/Users/Hidenori/Desktop/xlsx/rakuten1160-20150201-plan-number.csv") File "/Applications/Python 2.7/program/pythontest/text_test.py", line 29, in collect copyfile(filename, tempdir) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py", line 83, in copyfile with open(dst, 'wb') as fdst: IOError: [Errno 21] Is a directory: '/var/folders/27/dvh8p3j909x93tgqmlvw2tvm0000gn/T/tmpJ1EUKg' 対処法を教えてください><
ShinpeiYamamoto

2015/07/19 03:00 編集

申し訳ない。バグですね。。。ごめんなさい。 copyfile(filename, tempdir)を copyfile(filename, os.path.join(tempdir,os.path.basename(filename))) に差し替えてください。 コピー先はファイル名まで指定する必要がありました。やっぱりテストなしでは色々でますね。苦笑
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問