#python #python-3.x #web-scraping #beautifulsoup
Вопрос:
Я пытаюсь извлечь четыре поля с веб-страницы, используя библиотеку BeautifulSoup. Трудно идентифицировать поля по отдельности, и именно по этой причине я обращаюсь за помощью.
Иногда присутствуют оба письма, но это не всегда так. Я использовал индексацию для захвата электронной почты для этого примера, но, безусловно, это худшая идея. Более того, при следующей попытке я могу разобрать только заголовок письма, а не адрес электронной почты.
Я пробовал с (минимальный рабочий пример):
from bs4 import BeautifulSoup
html = """
<p>
<strong>
Robert Romanoff
</strong>
<br/>
146 West 29th Street, Suite 11W
<br/>
New York, New York 10001
<br/>
Telephone: (718) 527-1577
<br/>
Fax: (718) 276-8501
<br/>
Email:
<a href="mailto:robert@absol.com">
robert@absol.com
</a>
<br/>
Additional Contact: William Locantro
<br/>
Email:
<a href="mailto:bill@absol.com">
bill@absol.com
</a>
</p>
"""
soup = BeautifulSoup(html,"lxml")
container = soup.select_one("p")
contact_name = container.strong.text.strip()
contact_email = [i for i in container.strings if "Email" in i][0].strip()
additional_contact = [i.strip() for i in container.strings if "Additional Contact" in i.strip()][0].strip('Additional Contact:')
additional_email = [i for i in container.strings if "Email" in i][1].strip()
print(contact_name,contact_email,additional_contact,additional_email)
Выходной ток:
Robert Romanoff Email: William Locantro Email:
Ожидаемый результат:
Robert Romanoff robert@absol.com William Locantro bill@absol.com
Комментарии:
1. Не могли бы вы поделиться URL-адресом. Трудно найти решение, которое работало бы для всех случаев.
2. Проверьте правку @Ram.
Ответ №1:
Для более сложного анализа html/xml вам следует взглянуть на xpath
то, что позволяет использовать очень мощные правила выбора.
В python он доступен в parsel
пакете.
from parsel import Selector
html = '...'
sel = Selector(html)
name = sel.xpath('//strong[1]/text()').get().strip()
email = sel.xpath("//text()[re:test(., 'Email')]/following-sibling::a/text()").get().strip()
name_additional = sel.xpath("//text()[re:test(., 'Additional Contact')]").re("Additional Contact: (. )")[0]
email_additional = sel.xpath("//text()[re:test(., 'Additional Contact')]/following-sibling::a/text()").get().strip()
print(name, email, name_additional, email_additional)
# Robert Romanoff robert@absol.com William Locantro bill@absol.com
Комментарии:
1. Я был загипнотизирован вашим ответом, поэтому забыл спросить, что
re:test()
здесь происходит. Спасибо.2.
re:test
это функция xpath, которая выполняет проверку соответствия регулярных выражений на целевом объекте. Сигнатура функции таковаre:test(target, pattern, flags)
. В этом случае мы проверяем.
, что относится к «я» (текстовый узел), и наш шаблон"Additional Contact"
, и мы не предоставляем никаких флагов (в качестве альтернативы вы можете указать"i"
, например, игнорировать регистр). Другим способом выполнения той же функции было бы использованиеcontains()
функции:[contains(., "Additional Contact")]
—re:test()
это просто более продвинутая версия этого.3. подробнее об этом в
parsel
документах: parsel.readthedocs.io/en/latest/…
Ответ №2:
Ты можешь сделать вот так.
- Выберите тот
<div>
, в котором есть нужные вам данные. - Создайте список данных, присутствующих внутри выбранного выше
<div>
- Повторите список и извлеките необходимые данные.
Вот код:
from bs4 import BeautifulSoup
import requests
url = 'http://www.nyeca.org/find-a-contractor-by-name/'
r = requests.get(url)
soup = BeautifulSoup(r.text,"lxml")
d = soup.find_all('div', class_='sabai-directory-body')
for i in d:
x = i.text.strip().split('n')
data = [x[0].strip()]
for item in x:
if item.startswith('Email'):
data.append(item.split(':')[1].strip())
elif item.startswith('Additional'):
data.append(item.split(':')[1].strip())
print(data)
Содержит список сведений о подрядчике, а также дополнительные сведения (если таковые имеются).
['Ron Singh', 'rsingh@atechelectric.com']
['George Pacacha', 'Office@agvelectricalservices.com']
['Andrew Drazic', 'ADrazic@atjelectrical.com']
['Albert Barbato', 'Abarbato@abelectriccorp.com']
['Ralph Sica', 'Ralph.Sica@abm.com', 'Henry Kissinger', 'Henry.Kissinger@abm.com']
['Robert Romanoff', 'robert@absoluteelectric.com', 'William Locantro', 'bill@absoluteelectric.com']
.
.
Ответ №3:
Вот решение, которое вы можете попробовать,
import re
soup = BeautifulSoup(html, "lxml")
names_ = [
soup.select_one("p > strong").text.strip(),
soup.find(text=re.compile("Additional Contact:")).replace('Additional Contact:', '').strip()
]
email_ = [i.strip() for i in soup.find_all(text=re.compile("absol"))]
print(" ".join(i " " j for i, j in zip(names_, email_)))
Robert Romanoff robert@absol.com William Locantro bill@absol.com