Python, BeautifulSoup, re: Как конвертировать извлеченные тексты в словарь из Интернета? - PullRequest
0 голосов
/ 31 мая 2018

Я сделал скрипт, использующий BeautifulSoup для извлечения определенной информации из Интернета.Единственная проблема заключается в том, что я не знаю, как преобразовать результаты в словарь, и если я сделаю это, код будет похож на спагетти.Я не уверен, что этот код, который я написал, приемлем для Pythonic.Последний элемент Species должен иметь биномиальную номенклатуру, такую ​​как "Lycaon pictus", а строки после "pictus" должны игнорироваться.Нужна помощь.

скрипт

from urllib.request import Request, urlopen
from bs4 import BeautifulSoup
import re

url = "https://www.itis.gov/servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=183833#null"
page = urlopen(Request(url, headers={'User-Agent': 'Mozilla/5.0'}))
soup = BeautifulSoup(page, 'html.parser')
results = soup.findAll('tr')
for result in results:
    text = result.get_text().strip()
    pattern = r"^(Kingdom|Phylum|Division|Class|Order|Family|Genus|Species)[\w]+"
    if re.match(pattern, text):
        res = text.split('\n', 1)[0].strip()
        print(res)

вывод скрипта

KingdomAnimalia
PhylumChordata
ClassMammalia Linnaeus, 1758
OrderCarnivora Bowdich, 1821
FamilyCanidae Fischer, 1817
GenusLycaon Brookes, 1827
SpeciesLycaon pictus (Temminck, 1820) – African hunting dog, African Wild Dog, Painted Hunting Dog

ожидаемый результат

{
    'Kingdom': 'Animalia',
    'Phylum': 'Chordata',
    'Class': 'Mammalia',
    'Order': 'Carnivora',
    'Family': 'Canidae',
    'Genus': 'Lycaon',
    'Species': 'Lycaon pictus'
}

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Для конкретного приведенного примера это работает:

...
results = soup.findAll('tr')
my_dict = {}
for result in results:
    text = result.get_text().strip()
    pattern = r"^(Kingdom|Phylum|Division|Class|Order|Family|Genus|Species)[\w]+"
    if re.match(pattern, text):
        res = text.split('\n', 1)[0].strip()
        pieces = re.findall(r'[A-Z][ a-z]*', res)
        my_dict[pieces[0]] = pieces[1]
print(my_dict)

Вывод:

{'Kingdom': 'Animalia', 'Phylum': 'Chordata', 'Class': 'Mammalia',
 'Order': 'Carnivora', 'Family': 'Canidae', 'Genus': 'Lycaon',
 'Species': 'Lycaon pictus'}

Это в значительной степени зависит от точного форматирования, указанного в примере выше.Например, если веб-сайт имеет 'Lycaon Pictus' с капиталом 'P' для 'Species', то соответствующая запись в словаре будет просто 'Lycaon' вместо 'Lycaon Pictus'.

0 голосов
/ 31 мая 2018

«результат» здесь выглядит примерно так:

<td align="left" class="body" width="2%"> </td>
<td align="left" class="body" valign="top" width="24%">Kingdom</td>
<td class="datafield" valign="top" width="71%"><a href="SingleRpt?search_topic=TSN&amp;search_value=202423">Animalia</a> 
 – Animal, animaux, animals</td>
<td class="body" width="5%"> </td>

Когда вы используете .get_text (), он превращается в

'\xa0KingdomAnimalia\xa0\n – Animal, animaux, animals\n\xa0'

Так что при сопоставлении вы должны использовать свой старый«результат» и разделить столбцы вверх.Например:

if re.match(pattern, text)) :
    pieces = result.findAll('td')

, а затем использовать эти кусочки для поиска вашей информации, например

for p in pieces:
    print(p.get_text())

Конечно, вы не можете ожидать, что он вернет словарь, когда вы работаете со строкамии не занимаемся составлением карт в первую очередь.Таким образом, вы должны создать его перед запуском цикла for, назовем его dictionary

if re.match(pattern, text):
    p = result.findAll('td')
    rank = p[1].get_text().strip()
    taxon = p[2].get_text().split('\xa0')[0]
    dictionary[rank] = taxon

Это даст вам словарь, который вы ищете

...