Гузариш ба мундариҷа
Мавзӯи 5 аз 5

Тоза кардан ва тағйир додани HTML

Чаро HTML-ро тағйир медиҳем

Барои мутолиа, ҷустуҷӯ ё бойгонӣ саҳифа аксар вақт чизҳои зиёдатӣ дорад: панелҳои хизматӣ, услубҳои дохилӣ ва тавзеҳҳои такрорӣ. Баъзан матнро нигоҳ дошта, пардаашро бардоштан лозим аст; баъзан тамоми блокро нест кардан. BeautifulSoup имкон медиҳад дарахтро таҳрир карда, баъд HTML ё матни нав гирем.

Амалҳои дарахт объектҳои хотираро тағйир медиҳанд. Онҳо файли аслиро аз нав наменависанд ва саҳифаи серверро иваз намекунанд. Аз ин рӯ аввал сатрро таҳлил карда, табдилҳоро анҷом диҳед, натиҷаро санҷед ва баъд нигоҳ доред. Интихоби амал ба он вобаста аст, ки чӣ бояд монад: мундариҷа, худи теги буридашуда ё ҳеҷ чиз.

1. Нест кардан, буридан ё кушодани парда

decompose() тегро бо мундариҷааш нобуд мекунад. extract() тегро аз дарахт ҷудо карда бармегардонад: порчаро омӯхтан ё ба ҷойи дигар гузоштан мумкин аст. unwrap() танҳо пардаро гирифта, мундариҷаро дар ҷойи пешина мегузорад. Ин амалҳо ба партофтани қуттӣ бо чизҳояш, кӯчондани қуттӣ ва гирифтани танҳо бастабандӣ монанданд.

from bs4 import BeautifulSoup

html = "<div>A<b>B</b>C</div>"
for operation in ["decompose", "extract", "unwrap"]:
    soup = BeautifulSoup(html, "html.parser")
    tag = soup.b
    result = getattr(tag, operation)()
    print(operation, str(soup))
    if operation == "extract":
        print(result.get_text())

Натиҷа:

decompose <div>AC</div>
extract <div>AC</div>
B
unwrap <div>ABC</div>

2. Тағйир додани мундариҷа ва атрибутҳо

Ба tag.string қимат додан тамоми мундариҷаи тег, аз ҷумла унсурҳои дохилии пешинаро бо як сатр иваз мекунад. Қиматдиҳӣ аз рӯйи калид атрибутро тағйир медиҳад. del tag["style"] онро ҳангоми мавҷудият мебардорад. Барои иваз кардани як гиреҳ replace_with мувофиқ аст: сохтори дигар мемонад. Пеш аз нест кардани атрибути ихтиёрӣ has_attr-ро санҷед.

from bs4 import BeautifulSoup

soup = BeautifulSoup('<p style="color:red">A <b>B</b></p>', "html.parser")
soup.b.replace_with("C")
soup.p["class"] = "lead"
if soup.p.has_attr("style"):
    del soup.p["style"]
print(soup)
soup.p.string = "D"
print(soup)

Натиҷа:

<p class="lead">A C</p>
<p class="lead">D</p>

3. Сохтан ва гузоштани тег

new_tag аз худи soup даъват шуда, теги ҷудогона месозад. Сохтан ҳанӯз онро ба ҳуҷҷат намегузорад. append гиреҳро ба охири мундариҷа ва insert(0, ...) ба аввал мегузорад. Сатр матн ҳисоб мешавад: "<b>A</b>" худ аз худ тег намешавад. Барои сохтор объекти тег созед.

from bs4 import BeautifulSoup

soup = BeautifulSoup("<p>A</p>", "html.parser")
link = soup.new_tag("a", href="/next")
link.string = "B"
print(soup)
soup.p.append(link)
soup.p.insert(0, "0: ")
print(soup)

Натиҷа:

<p>A</p>
<p>0: A<a href="/next">B</a></p>

4. Гирифтани HTML ё матн

str(soup) дарахти тағйирёфтаро ба HTML табдил медиҳад. prettify() намуди чандсатраи дорои фосилагузориро барои дидан месозад, на нусхаи ороиши аслӣ. get_text() матнро ҷамъ мекунад. Дар BeautifulSoup 4.12.3 ҳангоми таҳлили одии HTML матни script ва style ба get_text()-и пешфарз дохил намешавад, вале худи унсурҳо то нест кардан дар HTML мемонанд.

from bs4 import BeautifulSoup

soup = BeautifulSoup("<div><script>x()</script><p>A</p></div>", "html.parser")
print(soup.get_text())
print(soup.find("script") is not None)
soup.script.decompose()
print(str(soup))
print(soup.prettify(), end="")

Натиҷа:

A
True
<div><p>A</p></div>
<div>
 <p>
  A
 </p>
</div>

5. Сохтор ва қолабҳои матнӣ

BeautifulSoup ҳудудро аз рӯйи тегҳо интихоб мекунад, модули re бошад, қолаби такроршавандаро дар матн меҷӯяд: масалан, нишонаи ID- ва рақамҳо. Ифодаи мунтазам дар ин ҷо ба матни блоки аллакай ёфтшуда татбиқ мешавад, на ба таҳлили тамоми HTML. re.compile қолаб месозад; онро ба ҷустуҷӯи номи тегҳо ё гиреҳҳои матнӣ низ додан мумкин аст.

import re
from bs4 import BeautifulSoup

html = "<aside>ID-99</aside><main><h4>A</h4><p>ID-12 <b>ID-34</b></p></main>"
soup = BeautifulSoup(html, "html.parser")
text = soup.main.get_text(" ")
print(re.findall(r"ID-\d+", text))
print([tag.name for tag in soup.find_all(re.compile(r"^h[1-6]$"))])
print([str(node) for node in soup.main.find_all(string=re.compile("ID-"))])

Натиҷа:

['ID-12', 'ID-34']
['h4']
['ID-12 ', 'ID-34']

6. Ба шакли ягона овардан ва тартиб

Ба шакли ягона овардан навиштаҳои гуногуни як арзишро яксон мекунад. Масалан, фосилаҳои канориро мебардоранд ва регистрро иваз мекунанд. set такрорҳоро нест мекунад, sorted тартиб медиҳад. Инро мувофиқи шарт иҷро кунед: баъзан регистри аслӣ ё тартиби пайдоиш муҳим аст. Ҷустуҷӯи чанд навъи тег бо як даъват тартиби умумии онҳоро нигоҳ медорад, вале интихобҳои алоҳида ва пайвастани баъдӣ метавонанд онро вайрон кунанд.

from bs4 import BeautifulSoup

soup = BeautifulSoup("<h4> B </h4><h2>A</h2><h4>b</h4>", "html.parser")
tags = soup.find_all(["h2", "h4"])
print([tag.name for tag in tags])
values = {tag.get_text().strip().lower() for tag in tags}
print(sorted(values))

Натиҷа:

['h4', 'h2', 'h4']
['a', 'b']

Дар дохил чӣ рӯй медиҳад

Таҳрир робитаҳои гиреҳҳои дарахтро тағйир медиҳад. Баъд аз extract тег дигар ба волидайни пешина тааллуқ надорад, вале объекти мустақил мемонад. Баъд аз decompose гиреҳи нобудшударо ҳамчун теги одӣ истифода набаред. Агар тағйирёбанда ба тег ишора кунад, тағйир аз он тавассути soup ҳам дида мешавад: ин як объект аст.

Барои несткунии оммавӣ аввал бо select ё find_all рӯйхат гиред ва баъд дарахтро тағйир диҳед. Ин рӯйхати объектҳои интихобшуда аст, на дархости динамикӣ. Агар блокҳои интихобшуда дар дохили ҳам бошанд, нест кардани берунӣ дохилиҳоро ҳам нобуд мекунад; баъд аз он атрибутҳояшонро нахонед. Сатри аслии HTML то ошкоро навиштани натиҷа ҳамон мемонад.

Хатоҳои маъмул

1. Истифодаи decompose, вақте матн бояд монад. Бо парда мундариҷа ҳам нест мешавад. Барои гирифтани танҳо парда мисли мисоли якум unwrap-ро интихоб кунед.

2. Навиштани HTML ба .string. Он матни одӣ мешавад ва қавсҳои кунҷӣ рамзгузорӣ мешаванд. Бо new_tag тег сохта, объектро илова кунед. Методи clear() мундариҷаи пешинаро бардошта, худи тегро нигоҳ медорад.

from bs4 import BeautifulSoup

soup = BeautifulSoup("<p></p>", "html.parser")
soup.p.string = "<b>A</b>"
print(soup)
soup.p.clear()
tag = soup.new_tag("b")
tag.string = "A"
soup.p.append(tag)
print(soup)

Натиҷа:

<p>&lt;b&gt;A&lt;/b&gt;</p>
<p><b>A</b></p>

3. Фаромӯш кардан, ки .string = ... фарзандони пешинаро мебардорад. Ба сатри тамоми теги p қимат додан ҷудокунии пешинаи b-ро нест мекунад. Барои иваз кардани танҳо порчаи ҷудошуда бо p.b ё replace_with кор кунед. Мисоли тағйирдиҳии боло нишон медиҳад, ки чӣ тавр ба ҷойи ду гиреҳ як матн мемонад.

4. Гумон кардан, ки get_text() фосилаҳои автоматӣ мегузорад. Матни тегҳои ҳамсоя метавонад часпад. Ҷудокунаки ошкоро барои ҷустуҷӯи арзишҳои ҷудогона ёрӣ медиҳад, вале онро мувофиқи масъала интихоб кунед. Қолаб набояд тасодуфан рақамҳои порчаи ҳамсояро ҳам гирад.

import re
from bs4 import BeautifulSoup

soup = BeautifulSoup("<p><b>ID-1</b><i>2</i></p>", "html.parser")
print(re.findall(r"ID-\d+", soup.p.get_text()))
print(re.findall(r"ID-\d+", soup.p.get_text(" ")))

Натиҷа:

['ID-12']
['ID-1']

Ёддошт

Амал Натиҷа
decompose() Нест кардани тег бо мундариҷа
extract() Буридан ва баргардондани тег
unwrap() Гирифтани парда ва нигоҳ доштани мундариҷа
tag.string = ... Иваз кардани тамоми мундариҷа бо матн
replace_with(...) Иваз кардани як гиреҳ
new_tag, append, insert Сохтани тег ва гузоштани гиреҳ
str(soup), prettify() HTML; HTML бо фосилагузорӣ
get_text, re.findall Ҷамъ кардани матн; ёфтани қолабҳо дар сатр
lower, set, sorted Регистр, ягонагӣ, тартиб