回答編集履歴

2

誤記修正

2015/07/01 08:11

投稿

ShinpeiYamamoto
ShinpeiYamamoto

スコア540

test CHANGED
@@ -60,7 +60,7 @@
60
60
 
61
61
  # ファイルを何かが開いていたら厄介なので、一旦テンポラリにコピーする
62
62
 
63
- yleid collect(os.path.join(root, file))
63
+ yield collect(os.path.join(root, file))
64
64
 
65
65
 
66
66
 

1

追記

2015/07/01 08:11

投稿

ShinpeiYamamoto
ShinpeiYamamoto

スコア540

test CHANGED
@@ -345,3 +345,295 @@
345
345
  main()
346
346
 
347
347
  ```
348
+
349
+
350
+
351
+ ---
352
+
353
+ (2015/06/28追記)
354
+
355
+
356
+
357
+ ssh(sftp)経由でリモートのパスを舐め、ファイルを取得してくるように改変します。
358
+
359
+ その前に、サードパーティのモジュールをインストールします。
360
+
361
+
362
+
363
+ ```lang-sh
364
+
365
+ pip install paramiko
366
+
367
+ ```
368
+
369
+ ※paramikoのインストールには色々と厄介なことがあるようです。linuxでは起こりにくいとは思いますが、ハッシュ化や暗号化モジュールがうまく入らない場合、また情報をください。
370
+
371
+
372
+
373
+ sshでファイルを収集するプログラムは次のような感じでできます。
374
+
375
+ ssh経由でファイルを探す部分は手作りですね。walkを適当に拾ったのを参考に自作しました。(黒)
376
+
377
+ 1件だけ懸念点があり、SHHで接続に失敗する場合、直接鍵ファイルを指定する必要があるかもしれません。
378
+
379
+
380
+
381
+ コメントにしている、以下のコードを有効にし、鍵ファイルへのパスを直接指定してください。
382
+
383
+ conn.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
384
+
385
+
386
+
387
+ 以下、対象ホストSSH接続し、ファイルを収集、内容をデータベースに書き出すサンプルです。
388
+
389
+ データベースのテーブル定義などは考慮していません。適時修正ください。
390
+
391
+
392
+
393
+ ```lang-python
394
+
395
+ # -*- coding: utf-8 -*-
396
+
397
+
398
+
399
+ import re
400
+
401
+ import os
402
+
403
+ from tempfile import mkdtemp
404
+
405
+
406
+
407
+ import paramiko
408
+
409
+ from stat import S_ISDIR
410
+
411
+
412
+
413
+ from sqlalchemy import create_engine
414
+
415
+ from sqlalchemy.orm import sessionmaker
416
+
417
+ from sqlalchemy.ext.declarative import declarative_base
418
+
419
+ from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, Sequence
420
+
421
+
422
+
423
+ HOST_ADDRESS = "XX.XX.XX.XX" #データ収集時の接続先ホストIPアドレス
424
+
425
+ SSH_PORT = 22 #SSH接続ポート
426
+
427
+ SSH_PASSWORD = "XXXXXXXX" #SSH接続パスワード
428
+
429
+ SSH_USERNAME = "wheeluser" #SHH接続ユーザ名
430
+
431
+
432
+
433
+ FILENAME_PATTERN = '20150601' #収集対象とするファイル名のパターン
434
+
435
+ ROOT_PATH = r'/home/username/' #収集するファイルが存在するトップディレクトリ
436
+
437
+ CONNECT_STRING = 'mysql://<ユーザ名>:<パスワード>@<ip>/<db名>' #DB接続文字列
438
+
439
+
440
+
441
+ # ローカルがwindows機である場合、os.path.joinのパスのデリミタで問題がでるのでその対処
442
+
443
+ RELATIONSHIP_TO_HOST = "posix_to_posix" # "posix_to_posix" / "nt_to_posix" / "posix_to_nt"
444
+
445
+
446
+
447
+ if RELATIONSHIP_TO_HOST == "posix_to_posix":
448
+
449
+ from os import path as remote_path
450
+
451
+ elif RELATIONSHIP_TO_HOST == "nt_to_posix":
452
+
453
+ import posixpath as remote_path
454
+
455
+ elif RELATIONSHIP_TO_HOST == "posix_to_nt":
456
+
457
+ import ntpath as remote_path
458
+
459
+
460
+
461
+ import logging
462
+
463
+ from datetime import datetime
464
+
465
+ logging.basicConfig(filename=datetime.today().strftime(r"%Y%m%d_%H%M%S")+'.log', level=logging.DEBUG)
466
+
467
+
468
+
469
+ r = re.compile("[a-zA-Z]+-(?P<date>\d{8})\.txt") #対象ファイル名を示す正規表現を定義。
470
+
471
+
472
+
473
+ Base = declarative_base()
474
+
475
+
476
+
477
+ class Data(Base):
478
+
479
+ __tablename__ = 'tablename'
480
+
481
+ id = Column('id', Integer, Sequence('id_seq'), primary_key=True)
482
+
483
+ somedata = Column('somedata', String(512))
484
+
485
+
486
+
487
+ def __init__(self, somedata):
488
+
489
+ self.somedata = somedata
490
+
491
+ def __repr__(self):
492
+
493
+ return "<Data('%s',...)>" % (self.somedata)
494
+
495
+
496
+
497
+
498
+
499
+ def walk(sftp, path):
500
+
501
+ current = path
502
+
503
+ files = []
504
+
505
+ folders = []
506
+
507
+ for item in sftp.listdir_attr(current):
508
+
509
+ if S_ISDIR(item.st_mode):
510
+
511
+ folders.append(item.filename)
512
+
513
+ else:
514
+
515
+ files.append(item.filename)
516
+
517
+ yield current, folders, files
518
+
519
+ for folder in folders:
520
+
521
+ for x in walk(sftp, remote_path.join(path, folder)):
522
+
523
+ yield x
524
+
525
+
526
+
527
+ def collect(sftp, filename):
528
+
529
+ tempdir = mkdtemp()
530
+
531
+ dist = os.path.join(tempdir, os.path.basename(filename))
532
+
533
+ logging.info("copy file from " + filename + " to " + dist)
534
+
535
+ sftp.get(filename, dist, lambda x, y: (logging.warning("File tranceport fail !!!") if x!=y else logging.info("File tranceport success.")))
536
+
537
+ return dist
538
+
539
+
540
+
541
+ def gen_filelist(sftp, path):
542
+
543
+ for root, dirs, files in walk(sftp, path):
544
+
545
+ for file in files:
546
+
547
+ m = r.match(file)
548
+
549
+ if(m and FILENAME_PATTERN in m.groupdict().values()):
550
+
551
+ # ファイルを何かが開いていたら厄介なので、一旦テンポラリにコピーする
552
+
553
+ yield collect(sftp, remote_path.join(root, file))
554
+
555
+
556
+
557
+ def read_line(data):
558
+
559
+ #データを読み出す。例えばcsvファイルをカンマで分けるとか。
560
+
561
+ #今回は、ORMのクラスにデータを格納してそのまま返します。
562
+
563
+ return Data(data)
564
+
565
+
566
+
567
+ def read(filename):
568
+
569
+ with open(filename, "r") as f:
570
+
571
+ lines = []
572
+
573
+ for line in f.readlines():
574
+
575
+ if(line.strip() != ""):
576
+
577
+ lines.append(read_line(line))
578
+
579
+ return lines
580
+
581
+
582
+
583
+
584
+
585
+ def main():
586
+
587
+ #SQLAlchemyの準備
588
+
589
+ engine = create_engine(CONNECT_STRING, encoding='utf-8', echo=True)
590
+
591
+ Session = sessionmaker(bind=engine)
592
+
593
+ session = Session()
594
+
595
+
596
+
597
+ #SFTP接続の準備
598
+
599
+ conn = paramiko.SSHClient()
600
+
601
+ conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
602
+
603
+ #conn.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) #鍵ファイルを直接指定する場合
604
+
605
+ conn.connect(HOST_ADDRESS, port=SSH_PORT, password=SSH_PASSWORD, username=SSH_USERNAME)
606
+
607
+ sftp = conn.open_sftp()
608
+
609
+
610
+
611
+ #ファイルの一覧を取得
612
+
613
+ files = gen_filelist(sftp, ROOT_PATH)
614
+
615
+
616
+
617
+ #ファイルの内容を取得
618
+
619
+ for file in files:
620
+
621
+ data = read(file)
622
+
623
+ session.add(data)
624
+
625
+
626
+
627
+ #データベースへ内容を登録
628
+
629
+ session.commit()
630
+
631
+
632
+
633
+ if __name__ == '__main__':
634
+
635
+ main()
636
+
637
+ ```
638
+
639
+