0

次のインスタンスを持つ html ファイルがあります。

<p>[CR][LF]
Here is the text etc

と:

...here is the last part of the text.[CR][LF]
</p>

ここで[CR]、 と[LF]はキャリッジ リターンと改行をそれぞれ表します。

これらの段落は、特定のクラスを持つ div 内にありますmy_class

この特定の div クラス内の段落タグをターゲットにして、次の置換を実行したいと考えています。

# remove new line after opening <p> tag
re.sub("<p>\n+", "<p>", div)
# remove new line before closing </p> tag
re.sub("<p>\n+", "<p>", div)

したがって、私のアプローチは次のとおりです。

  • htmlファイルを開く
  • 特定の div を分離する
  • <p>これらの div 内のタグを分離します
  • <p>これらのタグでのみ置換を実行します
  • 修正内容を元のhtmlファイルに書き戻す

これは私がこれまでに持っているものですが、置換に到達してファイルに書き戻すと、ロジックは失敗します:

from bs4 import BeautifulSoup
import re
# open the html file in read mode
html_file = open('file.html', 'r')
# convert to string
html_file_as_string = html_file.read()
# close the html file
html_file.close()
# create a beautiful soup object 
bs_html_file_as_string = BeautifulSoup(html_file_as_string, "lxml")
# isolate divs with specific class
for div in bs_html_file_as_string.find_all('div', {'class': 'my_class'}):
    # perform the substitutions
    re.sub("<p>\n+", "<p>", div)
    re.sub("\n+</p>", "</p>", div)
# open original file in write mode
html_file = open('file', 'w')
# write bs_html_file_as_string (with substitutions made) to file
html_file.write(bs_html_file_as_string)
# close the html file
html_file.close()

美しいスープのreplace_withも見てきましたが、ここに関連しているかどうかはわかりません。

編集:

以下の解決策は、re.sub を使用せずにタスクを完了する別の方法を示しました。

within a specific classただし、別の置換を実行する必要がありますが、 re.subを実行できるかどうかはまだわかりませんwithin a paragraph[CR][LF]具体的には、次の例では、すべてのを に置き換えたいと考えてい</p>\n<p>ます。私はこれがサブで起こることを想定していました:

re.sub('\n+', r'</p>\n<p>', str)

改行と改行を示す SciTE エディターのスクリーンショット:

ここに画像の説明を入力

デモ HTML (demo_html.html):

<html>
<body>
<p>lalalalalalalala</p>
<p>lalalalalalalala</p>
<div class="my_class">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum..consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit."Lorem ipsum dolor sit amet", consectetur adipisc'ing elit.Lorem ipsum dolor...sit amet, consectetur adipiscing elit..
Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit..
.....Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
<p>lalalalalalalala</p>
<p>lalalalalalalala</p>
</body>
</html>

デモ Python (demo_python.py):

from bs4 import BeautifulSoup
import re

with open('demo_html.html', 'r') as html_file:
    html_file_as_string = html_file.read()
bs_html_file_as_string = BeautifulSoup(html_file_as_string, "lxml")
for div in bs_html_file_as_string.find_all('div', {'class': 'my_class'}):
    for p in div.find('p'):
    p.string.replace('\n','</p>\n<p>')
with open('demo_html.html', 'w') as html_file:
    html_file.write(bs_html_file_as_string.renderContents())

print 'finished'
4

3 に答える 3

2

p.string.strip()先頭と末尾のスペースを削除します。

p.string.replaceWith(NEW_STRING)p タグのテキストを NEW_STRING に置き換えます。

from bs4 import BeautifulSoup

with open('file.html', 'r') as f:
    html_file_as_string = f.read()
soup = BeautifulSoup(html_file_as_string, "lxml")
for div in soup.find_all('div', {'class': 'my_class'}):
    for p in div.find('p'):
        p.string.replace_with(p.string.strip())
with open('file', 'w') as f:
    f.write(soup.renderContents())

ところで、re.sub(..)置換された文字列を返します。代替の元の文字列を置き換えるものではありません。

>>> import re
>>> text = '   hello'
>>> re.sub('\s+', '', text)
'hello'
>>> text
'   hello'

編集

編集された質問に一致するように編集されたコード:

from bs4 import BeautifulSoup

with open('file.html', 'r') as f:
    html_file_as_string = f.read()
soup = BeautifulSoup(html_file_as_string, "lxml")
for div in soup.find_all('div', {'class': 'my_class'}):
    for p in div.findAll('p'):
        new = BeautifulSoup(u'\n'.join(u'<p>{}</p>'.format(line.strip()) for line in p.text.splitlines() if line), 'html.parser')
        p.replace_with(new)
with open('file', 'w') as f:
    f.write(soup.renderContents())
于 2013-06-23T11:48:03.707 に答える
1

You need to check if the first and last content element of your p is a text node (an instance of bs4.NavigableString, which is a subclass of str). This should work:

from bs4 import BeautifulSoup, NavigableString
import re

html_file_as_string = """
<p>test1</p>

<p>
test2</p>
<p>test3
</p>

<p></p>

<p>
test4
<b>...</b>
test5
</p>

<p><b>..</b>
</p>

<p>
<br></p>

"""

soup = BeautifulSoup(html_file_as_string, "lxml")
for p in soup.find_all('p'):
    if p.contents:
        if isinstance(p.contents[0], NavigableString):
            p.contents[0].replace_with(p.contents[0].lstrip())
        if isinstance(p.contents[-1], NavigableString):
            p.contents[-1].replace_with(p.contents[-1].rstrip())

print(soup)

output:

<html><body><p>test1</p>
<p>test2</p>
<p>test3</p>
<p></p>
<p>test4
<b>...</b>
test5</p>
<p><b>..</b></p>
<p><br/></p>
</body></html>

Using regular expressions to parse/process html is almost always a bad idea.

于 2013-06-23T12:55:11.523 に答える
-1

for ループでの置換の結果は保存されません。次のようなものを試すことができます:

import re

strings = ['foo', 'bar', 'qux']

for k, s in enumerate(strings):
    strings[k] = re.sub('foo', 'cheese', s)
于 2013-06-23T11:54:05.460 に答える