最近の簡単・Python プログラミング

ウェブコーパスの作成については,規模が大きいのが厄介なだけで,ほとんどプログラミングをしていません.わずかな作業も Pythonシェルスクリプトを使えば簡単に片付いてしまいます.

同一内容ページの検出

アーカイブの中からメッセージダイジェスト(SHA-1)が同じになる HTML 文書を探すプログラムは,Python で簡単に書けました.アーカイブが大規模になるとメモリが不足してしまいますが,一部を入力として重複の割合を概算するくらいの用途には十分です.

# -*- coding: utf-8 -*-

import hashlib
import sys

# 自前のモジュールです.
import WebPageArchive

MIN_BODY_SIZE = 1024

def main(argv):
  digestMap = dict()
  for fileName in argv[1:]:
    webPageArchive = WebPageArchive.open(fileName)
    # アーカイブに含まれる HTML 文書を一つずつ読み込みます.
    for webPage in webPageArchive:
      # サーバの応答がエラーだった場合や,小さい文書は見なかったことにします.
      if webPage.code == 200 and len(webPage.body) >= MIN_BODY_SIZE:
        digest = hashlib.sha1(webPage.body).digest()
        if digest in digestMap:
          sys.stdout.write('Match:\n')
          sys.stdout.write('%s\n' % digestMap[digest])
          sys.stdout.write('%s\n' % webPage.url)
        else:
          digestMap[digest] = webPage.url
    webPageArchive.close()

if __name__ == '__main__':
  main(sys.argv)

アーカイブ内の HTML 文書を URL 順に整列

ポイントはホスト名の要素を逆順にすることくらいです.

# -*- coding: utf-8 -*-

import sys
import urlparse

import WebPageArchive

# URL から整列の基準として用いるキーを生成します.
def generateKey(webPage):
  parsedUrl = urlparse.urlparse(webPage.url)
  scheme = parsedUrl[0]
  netloc = parsedUrl[1]
  path = parsedUrl[2]
  params = parsedUrl[3]
  query = parsedUrl[4]
  fragment = parsedUrl[5]

  # ホスト名(netloc)の部分だけ要素を逆順にしています.
  # 理由は,後ろの要素ほど大きな意味を持つからです.
  # 後,http と https の違いは区別しない方が良い気がするので,
  # 一番後ろに移動してしまいました.
  return "%s%s%s%s%s" % ('.'.join(reversed(netloc.split('.'))),
    path, params, query, scheme)

def main(argv):
  webPageList = []
  for fileName in argv[1:]:
    webPageArchive = WebPageArchive.open(fileName)
    for webPage in webPageArchive:
      key = generateKey(webPage)
      webPageList.append((key, webPage))
    webPageArchive.close()

  # キーが昇順になるように整列します.
  webPageList.sort()
  for key, webPage in webPageList:
    webPage.write(sys.stdout)

if __name__ == '__main__':
  main(sys.argv)

整列済みアーカイブのマージ

ヒープキュー(優先順序付きキュー)を使いました.

# -*- coding: utf-8 -*-

import heapq
import sys

import WebPageArchive

def generateKey(webPage):
  # 上で使っているのと同じなので省略します.

def main(argv):
  heapQueue = []

  # 各アーカイブを開いて最初の HTML 文書と一緒に登録します.
  for fileName in argv[1:]:
    webPageArchive = WebPageArchive.open(fileName)
    webPage = webPageArchive.read()
    if webPage:
      key = generateKey(webPage)
      heapq.heappush(heapQueue, (key, webPage, webPageArchive))
    else:
      webPageArchive.close()

  # 後はキーが小さい HTML 文書から順に出力していきます.
  while heapQueue:
    (key, webPage, webPageArchive) = heapq.heappop(heapQueue)
    webPage.write(sys.stdout)

    # 出力した HTML 文書とペアになっているアーカイブについては,
    # 次の HTML 文書を読み込んで登録しなおします.
    webPage = webPageArchive.read()
    if webPage:
      key = generateKey(webPage)
      heapq.heappush(heapQueue, (key, webPage, webPageArchive))
    else:
      webPageArchive.close()

if __name__ == '__main__':
  main(sys.argv)

外部コマンド iconv を用いた文字コード変換

大体こんな感じでしょうか.外部コマンドを使うので効率が悪いものの,とりあえずは動きます.

import subprocess

def execIconv(text, fromEncoding, toEncoding = 'utf-8'):
  try:
    pipe = subprocess.Popen('iconv -s -f %s -t %s' % (fromEncoding, toEncoding),
      shell = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
    pipe.stdin.write(text)
    pipe.stdin.close()
    encodedText = pipe.stdout.read()
    pipe.stdout.close()
    if pipe.wait() != 0:
      return None
    return encodedText
  except:
    return None

# 絵文字は化けてしまいました.