(Clause de non-responsabilité: je suis un noob Python et web scraping, mais je fais de mon mieux pour apprendre).
J'essaie d'extraire 3 points de données clés d'études de recherche sur Clinicaltrials.gov. Ils ont une API, mais l'API ne capture pas les éléments dont j'ai besoin. Je veux obtenir une (1) brève description de l'étude, (2) le chercheur principal (IP) et (3) quelques mots-clés associés à l'étude. Je crois que mon code capture 1 et 3, mais pas 2. Je n'arrive pas à comprendre pourquoi je n'obtiens pas le nom du (des) chercheur (s) principal (s). Voici les deux sites que j'ai dans mon code:
https: // Clinicaltrials. gov / ct2 / show / NCT03530579 https://clinicaltrials.gov/ct2/show/NCT03436992
Voici mon code (je sais que le code PI est erroné, mais je voulais démontrer que j'ai essayé):
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 Réponses :
Vous pourrez peut-être utiliser le sélecteur suivant
i.e. 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)
Le . code > est un sélecteur de classe et le
[]
est un sélecteur attribut . L'espace entre est un combinateur descendant
a> précisant que l'élément récupéré à droite est un enfant de celui de gauche
Merci à tous! J'ai utilisé le code de QHarr et pour la plupart, cela a fonctionné. Cependant, lorsque j'ajoute une URL clinictrials.gov et qu'aucun PI n'est répertorié, j'obtiens une erreur "L'objet" NoneType "n'a pas d'attribut" texte ". Comment pourrais-je contourner cela?
Je vais éditer pour vous. Pouvez-vous fournir l'URL défaillante actuelle pour que je puisse ajouter au code
Merci! J'apprécie vraiment cela.
J'ai simplement utilisé des pandas pour obtenir les tables. cela renverra une liste de dataframes. Vous pouvez ensuite les parcourir pour rechercher le 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
Il y a donc de nombreuses façons de descendre dans l'arborescence DOM et votre chemin est très "cassant". Cela signifie que les sélecteurs que vous avez choisis pour commencer votre recherche sont extrêmement spécifiques et liés au style CSS qui peut changer beaucoup plus facilement que la structure du document dans son ensemble.
Mais si j'étais vous, je filtrerais certains nœuds sur certains critères, puis concentrez-vous sur ce groupe spécifique pendant que vous passez au crible le bruit.
Donc, en regardant ces URL que vous avez montrées, il semble que les données sont bien structurées et utilisent des tableaux. Sur cette base, nous pouvons faire des hypothèses telles que
principal_investigator = [ele for ele in refined_tables.findAll('td') if 'name' in ele.attrs['headers']][0].text
À ce stade, nous avons un candidat fort dans notre liste de tables_finies
qui pourrait en fait contenir notre table primaire et est idéalement de taille 1 en supposant que " Le filtre du chercheur principal "que nous avons utilisé ne se trouve nulle part ailleurs dans d'autres tables.
# 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()]
Ici, ce qui a été fait en regardant le site, c'est qu'ils utilisent l'attribut headers
pour attribuer le rôle de la balise td
dans la ligne du tableau.
Donc, en substance, pensez-y à partir d'un niveau supérieur et commencez à réduire les choses comme autant que possible en étapes simples pour vous aider à trouver ce que vous cherchez.
J'ai réussi à obtenir le PI, mais je ne vois pas non plus de mots-clés capturés. Quels sont les mots clés que vous essayez d'obtenir.