Очистка веб-страниц Python с помощью Beautifulsoup - невозможно извлечь главного исследователя из Clinicaltrials.gov - PullRequest
1 голос
/ 29 марта 2019

(Отказ от ответственности: я питон и веб-чистильщик, но я делаю все возможное, чтобы учиться).

Я пытаюсь извлечь 3 ключевых момента данных из исследований на Clinicaltrials.gov.У них есть API, но API не отражает то, что мне нужно.Я хочу получить (1) краткое описание исследования, (2) главный исследователь (PI) и (3) некоторые ключевые слова, связанные с исследованием.Я полагаю, что мой код захватывает 1 и 3, но не 2. Я не могу понять, почему я не получаю имя главного исследователя (ей).Вот два сайта, которые у меня есть в моем коде:

https://clinicaltrials.gov/ct2/show/NCT03530579 https://clinicaltrials.gov/ct2/show/NCT03436992

Вот мой код (я знаю, что код PI неверен, но я хотел продемонстрировать, чтоЯ пытался):

import pandas as pd
import requests
from bs4 import BeautifulSoup
import csv   

fields=['PI','Project_Summary', 'Keywords']
with open(r'test.csv', 'a') as f:
     writer = csv.writer(f)
     writer.writerow(fields)

urls = ['https://clinicaltrials.gov/ct2/show/NCT03436992','https://clinicaltrials.gov/ct2/show/NCT03530579']
for url in urls:

     response = requests.get(url)
     soup = BeautifulSoup(response.content, 'html.parser')
     #get_keywords
     for rows in soup.find_all("td"):
          k = rows.get_text()     
          Keywords = k.strip()
     #get Principal Investigator   
     PI = soup.find_all('padding:1ex 1em 0px 0px;white-space:nowrap;')

     #Get description    
     Description = soup.find(class_='ct-body3 tr-indent2').get_text()
     d = {'Summary2':[PI,Description,Keywords]} 

     df = pd.DataFrame(d)
     print (df)
     import csv   
     fields=[PI,Description, Keywords]
     with open(r'test.csv', 'a') as f:
          writer = csv.writer(f)
          writer.writerow(fields)

Ответы [ 3 ]

3 голосов
/ 29 марта 2019

Вы можете использовать следующий селектор

т.е. PI = soup.select_one('.tr-table_cover [headers=name]').text

import requests
from bs4 import BeautifulSoup  
urls = ['https://clinicaltrials.gov/ct2/show/NCT03530579', 'https://clinicaltrials.gov/ct2/show/NCT03436992','https://clinicaltrials.gov/show/NCT03834376']
with requests.Session() as s:
    for url in urls:
        r = s.get(url)
        soup = BeautifulSoup(r.text, "lxml")
        item = soup.select_one('.tr-table_cover [headers=name]').text if soup.select_one('.tr-table_cover [headers=name]') is not None else 'No PI'
        print(item)

. является селектором класса , а [] является селектором атрибута . Пробел между descendant combinator указывает, что элемент, полученный справа, является дочерним по отношению к элементу слева

2 голосов
/ 29 марта 2019

Я просто использовал панд, чтобы получить столы. это вернет список данных. Затем вы можете просто просмотреть их, чтобы найти PI:

tables = pd.read_html(url)
for table in tables:
    try:
        if 'Principal Investigator' in table.iloc[0,0]:
            pi =  table.iloc[0,1]
    except:
        continue
0 голосов
/ 29 марта 2019

Так что есть много способов пройтись по дереву DOM, и ваш путь очень «хрупок».Это означает, что выбранные вами селекторы, с которых нужно начать поиск, чрезвычайно специфичны и привязаны к стилю CSS, который может измениться намного проще, чем структура документа в целом.

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

Итак, глядя на те URL, которые вы показали, кажется, что данные структурированы аккуратно и с использованием таблиц.Исходя из этого, мы можем сделать некоторые предположения, такие как

  1. Это данные, которые находятся внутри таблицы
  2. В ней будет содержаться строка "главного исследователя"
# get all the tables in the page
tables = soup.find_all('table')
# now filter down to a smaller set of tables that might contain the info
refined_tables = [table for table in tables if 'principal investigator' in str(table).lower()]

На данный момент у нас есть сильный кандидат в нашем списке refined_tables, который на самом деле может содержать нашу первичную таблицу и в идеале имеет размер 1, если предположить, что фильтр «основного исследователя», который мы использовали, больше нигде в других таблицах.

principal_investigator = [ele for ele in refined_tables.findAll('td') if 'name' in ele.attrs['headers']][0].text

Именно здесь при просмотре сайта было использовано то, что они использовали атрибут headers для назначения роли тега td в строке таблицы.

Так что, по сути, просто подумайте об этом с верхнего уровня и начните сужать вещи как можно проще, используя простые шаги, чтобы помочь вам найти то, что вы ищете.

...