#python #regex #web-scraping #beautifulsoup
Вопрос:
Я пытаюсь очистить страницу Википедии «Геном». Я хочу очистить только подзаголовки, такие как «Происхождение термина», «Секвенирование и картирование», «Вирусные геномы», «Прокариотические геномы», «Эукариотические геномы», включая подзаголовки под этим, Размер генома и т. Д. и т. Д. . Для этого я написал следующий код, чтобы сделать это:
def filter_headers(self, web_soup):
# Grabs the headers from the web page
"""
:param web_soup: the raw web soup from the webpage
:return: header_soup: the headers in text form
"""
# TO DO: how to separate out just the main body content while including the
# title header
# Find all tags with a pattern like h1,h2,h3,h4...
headers = read_page_soup.find_all(re.compile(r'hd '))
return headers
Проблема в том, что независимо от того, насколько конкретно я отфильтровываю свои теги, я все равно получаю те же результаты с посторонними заголовками из меню навигации, такими как [Личные инструменты, пространства имен, Варианты, Представления…Инструменты,Печать/Экспорт, В Других Проектах, Языках]. Например, я попробовал это первым:
soup = read_page_soup.find(re.compile(r'hd '), {'class': 'mw-body-content'})
results = sr.filter_headers(soup)
for result in results:
print(result.text)
Затем я попробовал это, фильтруя через класс вывода mw-синтаксического анализатора, вот так:
soup = read_page_soup.find(re.compile(r'hd '), {'class': 'mw-parser-content'})
results = sr.filter_headers(soup)
for result in results:
print(result.text)
Я этого не понимаю. Дивы, над которыми я нависаю, даже не выделяют боковую панель википедии, когда я наведу на них курсор. Я хочу иметь возможность найти решение, которое работает для многих страниц Википедии, чтобы я мог очистить их все с одинаковыми результатами. Затем в будущем я надеюсь распространить это на другие веб-страницы, такие как Ars Technica. Так что, если кто-нибудь также может дать какие-либо справедливые предупреждения, я думаю, об использовании этого подхода для некоторого рудиментарного обхода веб-страниц. Если я не в состоянии разобраться в этом в каждом конкретном случае для какого-то рудиментарного обхода веб-страниц без приложения для обхода веб-страниц, дайте мне знать.
Ответ №1:
Вы пытаетесь получить тег заголовка, но оба класса, которые вы описываете, таковы divs
. Страницы Википедии , которые я тестировал, обычно имеют три mw-body-content
класса (все они есть div
, то же самое происходит с одним mw-parser-output
классом).:
<div id="siteNotice" class="mw-body-content">
<div class="mw-indicators mw-body-content">
<div id="bodyContent" class="mw-body-content">
Чтобы получить несколько заголовков страниц, вы можете использовать mw-body-content
класс, который у вас уже есть, но переключитесь на find_all
него и выберите третий элемент. С этого момента логика, используемая внутри filter_headers
с find_all
и регулярное выражение для header
, кажется, дает ожидаемый результат.
from bs4 import BeautifulSoup
import requests
import re
source = requests.get('https://en.wikipedia.org/wiki/Genome').text
read_page_soup = BeautifulSoup(source, 'lxml')
def filter_headers(web_soup):
headers = web_soup.find_all(re.compile(r'hd '))
return headers
soup = read_page_soup.find_all("div", {'class': 'mw-body-content'})[2]
results = filter_headers(soup)
for result in results:
hN = int(result.name[1:])*3-3
print(f"{result.name} {'-'*hN} {result.text}")
Выход
h2 --- Contents
h2 --- Origin of term[edit]
h2 --- Sequencing and mapping[edit]
h2 --- Viral genomes[edit]
h2 --- Prokaryotic genomes[edit]
h2 --- Eukaryotic genomes[edit]
h3 ------ Coding sequences[edit]
h3 ------ Noncoding sequences[edit]
h4 --------- Tandem repeats[edit]
h4 --------- Transposable elements[edit]
h5 ------------ Retrotransposons[edit]
h5 ------------ DNA transposons[edit]
h2 --- Genome size[edit]
h3 ------ Genome size due to transposable elements[edit]
...
...
Комментарии:
1. Я думаю, что это сработало, когда я изменил свой синтаксический анализатор с html на lxml и получал из запросов вместо чего-то более специализированного, такого как urlopen из запросов
2. Кроме того, считаете ли вы, что такой поэтапный подход к очистке веб-страниц будет хорошо работать для базового обхода веб-страниц?
3. @pancham2016 Для базового обхода веб-страниц я думаю, что этот подход подходит. Вам просто нужно обратить внимание на сайты, которые
dynamically
загружают данные с помощьюjavascript
. В этом контексте вам придется использовать что-то вроде Селена для получения данных.
Ответ №2:
Не могли бы вы просто взять эту информацию из li
элементов в списке содержимого #toc li
? Есть два дочерних spans
элемента , на каждого li
, содержащих нумерацию маркеров и имя:
import requests
from bs4 import BeautifulSoup as bs
r = requests.get('https://en.wikipedia.org/wiki/Genome')
soup = bs(r.content, 'lxml')
contents = [i.select_one('.tocnumber').text ' ' i.select_one('.toctext').text for i in soup.select('#toc li')]