PythonでHTMLに埋め込まれた固定形式データの解析
-
03-07-2019 - |
質問
GoogleのAppEngine APIを使用しています
from google.appengine.api import urlfetch
ウェブページを取得します。の結果
result = urlfetch.fetch("http://www.example.com/index.html")
はhtmlコンテンツの文字列です(result.content内)。問題は、解析したいデータが実際にはHTML形式ではないため、Python HTMLパーサーを使用してもうまくいかないと思います。 htmlドキュメントの本文にあるすべてのプレーンテキストを解析する必要があります。唯一の問題は、urlfetchがHTMLドキュメント全体の単一の文字列を返し、すべての改行と余分なスペースを削除することです。
編集: さて、私は別のURLをフェッチしようとしましたが、明らかにurlfetchは改行を削除しません、それはHTMLファイルをそのように提供したのは解析しようとしていた元のWebページでした... 編集の終了
ドキュメントが次のような場合:
<html><head></head><body>
AAA 123 888 2008-10-30 ABC
BBB 987 332 2009-01-02 JSE
...
A4A 288 AAA
</body></html>
result.contentは、urlfetchがフェッチした後、これになります:
'<html><head></head><body>AAA 123 888 2008-10-30 ABCBBB 987 2009-01-02 JSE...A4A 288 AAA</body></html>'
HTMLパーサーを使用してもbodyタグ間のデータの助けにはならないため、通常の表現を使用してデータを解析しますが、1行の最後の部分が次の行、そして私はそれを分割する方法がわかりません。試しました
result.content.split('\n')
and
result.content.split('\r')
しかし、結果のリストはすべて1つの要素でした。 Googleのurlfetch関数には、改行を削除しないオプションはありません。
このデータを解析する方法はありますか?別の方法で取得する必要がありますか?
事前に感謝します!
解決
ドキュメントのフォーマットは、あなたが投稿したものであることを理解しています。その場合、 Beautiful Soup のようなパーサーは良い解決策ではないことに同意します。
次のような正規表現を使用して、既に(BODYタグ間で)興味深いデータを取得していると仮定します
import re
data = re.findall('<body>([^\<]*)</body>', result)[0]
その後、次のように簡単になります:
start = 0
end = 5
while (end<len(data)):
print data[start:end]
start = end+1
end = end+5
print data[start:]
(注:このコードを境界ケースに対してチェックしませんでした。失敗することを期待しています。一般的なアイデアを示すのはここだけです)
他のヒント
考えられる唯一の提案は、固定幅の列があるかのように解析することです。 HTMLでは、改行は考慮されません。
ソースデータを制御できる場合は、HTMLではなくテキストファイルに入れます。
本文テキストが1つの長い文字列になったら、次のように分割できます。 これは、各レコードが26文字であることを前提としています。
body= "AAA 123 888 2008-10-30 ABCBBB 987 2009-01-02 JSE...A4A 288 AAA"
for i in range(0,len(body),26):
line= body[i:i+26]
# parse the line
編集:読解は望ましいことです。行の間にセパレータがない状態で一緒に実行されている行について少し見落としていました。これが全体のポイントになりますよね。だから、私の答えを気にしないでください、それは実際に関連性はありません。
各行が5つのスペースで区切られた列であることがわかっている場合、(htmlを削除したら)次のようなことを行うことができます(未テスト):
def generate_lines(datastring):
while datastring:
splitresult = datastring.split(' ', 5)
if len(splitresult) >= 5:
datastring = splitresult[5]
else:
datastring = None
yield splitresult[:5]
for line in generate_lines(data):
process_data_line(line)
もちろん、必要に応じて分割文字と列数を変更し(追加のパラメーターとしてジェネレーター関数に渡すこともできます)、必要に応じてエラー処理を追加できます。
文字列 s
を26文字のブロックに分割するためのさらなる提案:
リストとして:
>>> [s[x:x+26] for x in range(0, len(s), 26)]
['AAA 123 888 2008-10-30 ABC',
'BBB 987 2009-01-02 JSE',
'A4A 288 AAA']
ジェネレーターとして:
>>> for line in (s[x:x+26] for x in range(0, len(s), 26)): print line
AAA 123 888 2008-10-30 ABC
BBB 987 2009-01-02 JSE
A4A 288 AAA
s が非常に長い場合、Python 2.xで
range()
を xrange()
に置き換えます。