Pythonを使用してフォーラムをMS ExchangeからMySQLに変換します

ms exchangeパブリックフォルダーには、従業員が書くフォーラムがあります。これは非常に不便で抑制的です。 フォーラムを適切なソリューションに転送するには、作成済みのコンテンツを転送する必要もあります。 Googleは* bbに既製のコンバーターを見つけられなかったため、データベースで開始するために、Pythonで独自のコンバーターを作成することにしました。



最初に、私が最終的に取得したいもの、既存のコンテンツが通常のフォーラムの構造と一致するために必要なテーブルを理解する必要があります。



投稿のあるテーブル



コンテンツの主要部分はrtfであるため、すぐにHTMLで書くことはできません。 OutlookはもちろんSaveAsHTMLをサポートしていますが、結果は野生のポルノです。 私はrtfをhtmlに変換するためのいくつかの無料のライブラリを勉強しましたが、良いものは見つかりませんでした。 UnRtf Linuxユーティリティの変換が最適です(Windowsポートがありますが、キリル文字を消化しません)。 したがって、標準のpost_id、user_id、post_time、topic_id、post_textに加えて、rtfバージョンの投稿を保存する列が必要です。



CREATE TABLE `posts` ( `post_id` int(11) NOT NULL, `user_id` int(11) DEFAULT NULL, `post_time` int(11) DEFAULT NULL, `topic_id` int(11) DEFAULT NULL, `post_text` text, `rtf_file` varchar(45) DEFAULT NULL, PRIMARY KEY (`post_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
      
      







ユーザーとテーブル



 CREATE TABLE `users` ( `id` int(11) NOT NULL, -- id `mail` varchar(45) DEFAULT NULL, --ExchangeUserAddressEntry `exmail` varchar(100) DEFAULT NULL, --exchange , `exist` tinyint(1) DEFAULT NULL, --   , . .        . `name` varchar(100) DEFAULT NULL, --   `inab` tinyint(1) DEFAULT NULL, --      PRIMARY KEY (`id`), UNIQUE KEY `mail_UNIQUE` (`mail`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
      
      







テーマ表



 CREATE TABLE `topics` ( `id` int(11) NOT NULL, `title` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `title_UNIQUE` (`title`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
      
      







添付テーブル



 CREATE TABLE `attachments` ( `filename` varchar(45) NOT NULL, --  `name` varchar(255) DEFAULT NULL, --  `post_id` int(11) DEFAULT NULL, --id  `att_id` int(11) DEFAULT NULL, --id  PRIMARY KEY (`filename`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
      
      







Outlookオブジェクトが誤って処理されたテーブル



 CREATE TABLE `garbage` ( `id` int(11) NOT NULL, `rtf_file` varchar(45) DEFAULT NULL, -- post.rtf  `class` int(11) DEFAULT NULL, -- Outlook Item class, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
      
      







テーブルにデータを入力します



フォーラムは主にPostItemオブジェクトで構成され、「account@domain.com」ではなくExchangeUserAddressEntryを「O =最初の組織/ OU = EXCHANGE ADMINISTRATIVE GROUP(FYDIBOHF23SPDLT)/ CN = RECIPIENTS / CN = account」の形式で保存します。 したがって、まずアドレス帳からユーザーに関する必要なデータを取得する必要があります。このデータはExchangeUserAddressEntryにマップできます。



 import win32com.client #    Outlook.Application import pymysql.cursors #    mysql #  COM     AddressEntries object = win32com.client.Dispatch("Outlook.Application") ns = object.GetNamespace("MAPI") als = ns.AddressLists gal = als.Item("Global Address List") ent = gal.AddressEntries #   mysql    cnx = pymysql.connect(use_unicode=True, charset='utf8',user='outlook', password='password', host='server',database='outlook') cursor = cnx.cursor() id = 0 for rec in ent: id += 1 exmail = rec.Address # ExchangeUserAddressEntry name = rec.Name #    mail = rec.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x39FE001E") #     «account@domain.com» cursor.execute("INSERT INTO users (id, mail, exmail, name, inab) VALUES (%s, %s, %s, %s, 1);", (id, mail,exmail,name)) #    inab =1, . .      cursor.close() cnx.close()
      
      







準備が完了したら、コンテンツ解析に進みます



これを行うには、必要なフォルダーに接続し、すべてのオブジェクトのリストを取得して、それぞれから必要なデータを引き出す必要があります。 残念ながら、Outlookではファイル(xlsなど)をフォーラムにコピーできるため、PostItemおよびMailItemオブジェクトのみに関心があり、残りはゴミに送られます。



 import win32com.client import pymysql.cursors object = win32com.client.Dispatch("Outlook.Application") ns = object.GetNamespace("MAPI") tf = ns.GetFolderFromID('<EntryID>') #        EntryID i = 0 tmp = tf.items #   / tmp.sort('[ReceivedTime]',False) #     cnx = pymysql.connect(use_unicode=True, charset='utf8',user='outlook', password='password', host='server',database='outlook') cursor = cnx.cursor() for aaa in tmp: i +=1 rtf_file = "post_%d.rtf" %i #  rtf  if (aaa.Class == 45) or (aaa.Class == 43): #   postitem  mailitem aaa.SaveAs('c:\\temp\\low\\store\\%s' %rtf_file ,1) #Save as rtf #    ,    "c:\temp\low\store\" for ac in range(1,aaa.Attachments.Count,1): if aaa.Attachments.Item(ac).Type <> 6: #   ,  OLE document,     unrtf name = aaa.Attachments.Item(ac).FileName ext = name.split('.')[-1] filename = 'att_%d_%d.%s' %(i,ac,ext) aaa.Attachments.Item(ac).SaveAsFile('c:\\temp\\low\\store\\'+filename) cursor.execute("INSERT IGNORE INTO attachments (filename, name, post_id, att_id) VALUES (%s, %s, %s, %s);" ,(filename, name,i,ac)) #   exmail = aaa.SenderEmailAddress name = aaa.SenderName #,       users,   ,     user_id cursor.execute("SELECT id FROM users WHERE exmail = '%s' UNION SELECT max(id)+1 FROM users;" %(exmail)) res = cursor.fetchall() if len(res) == 2: user_id = res[0][0] cursor.execute("UPDATE users SET exist=1 WHERE id=%s;",user_id) #,    elif len(res) == 1: # ,   inab=0, . .   user_id = res[0][0] mail = exmail.split('=')[-1] if '@' not in mail: mail = mail+'@not.exist' #    -    AD    cursor.execute("INSERT INTO users (id,exist, exmail,mail, name, inab) VALUES (%s,1, %s, %s, %s, 0);" ,(user_id, exmail,mail,name)) #   topic = aaa.ConversationTopic #    outlook  ConversationTopic tq = """set @mmm = (SELECT IFNULL(max(id), 0)+1 FROM topics); INSERT IGNORE INTO topics(id,title) values (@mmm,%s);""" cursor.execute(tq,topic) #   #   posts cursor.execute("SELECT id FROM topics WHERE title = %s;",topic) topic_id =cursor.fetchall()[0][0] post_time = int(aaa.ReceivedTime) cursor.execute("INSERT IGNORE INTO posts (post_id, user_id, post_time, topic_id, rtf_file) VALUES (%s, %s, %s, %s, %s);",(i,user_id,post_time,topic_id,rtf_file)) else: #Garbage cursor.execute("INSERT IGNORE INTO garbage (id, rtf_file,class) VALUES (%s, %s,%s);",(i,rtf_file,aaa.Class)) cursor.close() cnx.close()
      
      





実行し、ゴミを確認し、コピーと貼り付けでフォーラムにスローされたいくつかのxlsファイルを取得しましたが、これは間違いなくフォーラムでは必要ありません。 投稿付きのRTFファイルと添付ファイル付きのファイルがストアフォルダに表示されました。 rtfファイルからhtmlテキストを作成し、post_textで埋め、残りの添付ファイルを引き出します。



最後のタッチ



上で書いたように、rtfの処理にはLinux UnRtfを使用します。そのため、ストアフォルダーをLinuxマシンにコピーします。 UnRtfはrtfファイルをhtmlコードに変換し、ファイルから画像と添付ファイルを抽出し、それらをimgタグで置き換えます。 添付ファイルは拡張子.wmfを取得します。画像である場合はすべて正常であり、開くことができます。また、何らかの種類のdocファイルである場合は、すでに読み取れません。 幸いなことに、Attachments.Item()。SaveAsFileを使用してこのような添付ファイルをすべて引き出したため、スクリプトはhtmlを抽出するだけでなく、wmfからimgタグを正しいリンクにすぐに修正します。



 #!/usr/bin/python import lxml.etree, pymysql, subprocess, os #lxml       #   , cpost -  post_id. /tmp/2del - ,  unrtf    def parsertf(cpost): p = subprocess.Popen('unrtf /opt/unrtf/store/post_%d.rtf'%cpost, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True, cwd = '/tmp/2del/') f = p.stdout.read() root = lxml.etree.HTML(f)[1] img_id = 0 for img in root.xpath('//img'): #      <img>,     img_id += 1 if img.attrib['src'][-4:] == '.wmf': # img src = *.wmf, -   . #,        outlook cursor.execute('SELECT filename,name FROM attachments WHERE post_id=%s AND att_id=%s;'%(cpost,img_id)) try: res = cursor.fetchall()[0] img.addnext(lxml.etree.fromstring('<a href="/path/%s">%s</a>'%(res[0],res[1]))) # ,    ,       except: # ,  wmf. attname = 'att_%d_%d'%(cpost,img_id)+img.attrib['src'][-4:] subprocess.Popen('mv -f /tmp/2del/%s /opt/unrtf/store/%s'%(img.attrib['src'], attname), shell=True) img.addnext(lxml.etree.fromstring('<a href="/path/%s">%s</a>'%(attname,attname))) img.getparent().remove(img) else: # imgname = 'img_%d_%d'%(cpost,img_id)+img.attrib['src'][-4:] subprocess.Popen('mv -f /tmp/2del/%s /opt/unrtf/store/%s'%(img.attrib['src'], imgname), shell=True) img.attrib['src'] = imgname root.remove(root[0]) #    from/to,  .. htmltext = lxml.etree.tostring(root) cursor.execute('UPDATE posts SET post_text=%s WHERE post_id=%s;',(htmltext,cpost)) subprocess.Popen('rm -rf /tmp/2del/*', shell=True) return htmltext cnx = pymysql.connect(use_unicode=True, charset='utf8',user='outlook', password='password', host='server',database='outlook') cursor = cnx.cursor() #     cursor.execute('SELECT post_id FROM posts;') posts = cursor.fetchall() for cpost in posts: parsertf(cpost[0]) cursor.close() cnx.close()
      
      





実行-フォーラムはmysqlに変換され、添付ファイルのあるフォルダーは/ opt / unrtf / store /にあります。 そこから、* .rtfを削除して、/ path /にフォーラムがあるWebサーバーに配置できます。 また、元のrtfファイルへのリンクを削除したり、投稿に追加したりすることはできません。RTFは、MS製品でさえ正常に動作できない、ひどい形式だからです。



おわりに



データベースを本格的なフォーラムにするには、まだ多くの作業を行う必要があります(phpbb / yaf.netに転送するためのフォーラム/コンバーターを作成するなど)が、最初のステップは既に完了しています。



» Gitコード



All Articles