[英]CSS selector for the first row of table on ClinicalTrials.gov
我在使用 web 從 ClinicalTrials.gov 抓取表格時遇到問題。
我正在嘗試在“搜索的術語和同義詞”表下提取第一行第一列中標記為“乳腺癌”的單詞的 CSS 選擇器。 這是該表的鏈接: https://clinicaltrials.gov/ct2/results/details?cond=breast+cancer
請參閱下面的屏幕截圖以了解我想要的條款:
CSS 選擇器.w3-padding-8:nth-child(1)
為我提供了第一列中的所有術語。 如果搜索詞是單個詞,例如“pembrolizumab”,則此方法有效,但如果搜索詞是兩個詞,例如“乳腺癌”,則表包含多行(“塊”)並且上述 CSS 選擇器返回所有詞從這些行。
編輯:這是@neilfws 建議的代碼:
search_term_processed <- unlist(stringr::str_replace("breast cancer", " ", "+"))
ctgov_url <- paste0("https://clinicaltrials.gov/ct2/results/details?term=", search_term_processed)
ct_page <- xml2::read_html(ctgov_url)
# extract related terms
ct_page %>%
# find elements that match a css selector
rvest::html_elements(".w3-padding-8:nth-child(1)") %>%
# retrieve text from element (html_text() is much faster than html_text2())
rvest::html_text()
有誰知道 CSS 選擇器僅提取第一列和第一行(“塊”)中的術語?
class w3-padding-8
的td
單元格包括您想要的列中列出的同義詞以及搜索和數據庫的(不需要的)研究數量。
因為每個同義詞條目后面都有兩個包含研究編號的單元格,所以以下策略可能有助於僅隔離同義詞列。
首先制作一個 html 集合 class w3-padding-8
的所有td
元素:
const cells = document.querySelectorAll('td.w3-padding-8');
然后,記錄第一個、第三個、第六個等單元格的innerText
(因此跳過那些包含研究編號的單元格):
for (let i=0; i<cells.length; i+=3) {
console.log(cells[i].innerText);
}
注意循環增量器使用i+=3
- 只允許包含要列出的同義詞的單元格 0,3,6... 等。
我在瀏覽器控制台上運行了這個,加載了你提供的鏈接,它返回了同義詞列表。 您可能需要修改的唯一部分是加載的表包含三個部分:“breast cancer”、“cancer”和“breast”,並且列表包含所有三個部分的同義詞。 您應該能夠隔離“乳腺癌”塊並應用相同的想法來檢索其同義詞列。
關鍵似乎是在使用i+=3
的每個同義詞之后跳過兩個單元格。
它是否解決了您的問題,而不是獲取表格?
library(tidyverse)
library(rvest)
"https://clinicaltrials.gov/ct2/results/details?cond=breast+cancer" %>%
read_html() %>%
html_table() %>%
.[[1]]
# A tibble: 30 × 3
Terms `Search Results*` `Entire Database**`
<chr> <chr> <chr>
1 Synonyms Synonyms Synonyms
2 breast cancer 12,002 studies 12,002 studies
3 Breast Neoplasms 9,539 studies 9,539 studies
4 breast carcinomas 917 studies 917 studies
5 Breast tumor 159 studies 159 studies
6 cancer of the breast 66 studies 66 studies
7 Neoplasm of breast 61 studies 61 studies
8 cancer of breast 40 studies 40 studies
9 Carcinoma of the Breast 33 studies 33 studies
10 CARCINOMA OF BREAST 32 studies 32 studies
# … with 20 more rows
# ℹ Use `print(n = ...)` to see more rows
問題:
我不相信 rvest 目前不可能做到這一點,因為它依賴於選擇器級別 3,在引擎蓋下,它只允許一個帶有否定的簡單選擇器,即在:not() 內部。 這些行都處於相同的 DOM 級別,您想要的是能夠從“第一”批次中過濾掉后面的行。
對於4 級選擇器,允許在:not() 中使用選擇器列表的方法是:
tr[style]:nth-child(1) ~ tr:not( tr[style]:nth-child(n+2) ~ tr):not([style]) td:first-child
以上只是選擇器級別 4 的一個工作示例。還有其他更好的變體。
我認為這是幕后選擇器的實現細節(通過xml2?)。 比較以下內容:
parse_simple_selector,它是一個選擇器 function,反對偽 class 否定中存在非簡單選擇器。
library(rvest)
link <- 'https://clinicaltrials.gov/ct2/results/details?cond=breast+cancer'
page <- read_html(link)
selector_list <- 'tr[style]:nth-child(1) ~ tr:not(tr[style]:nth-child(n+2) ~ tr):not([style]) td:first-child'
page |> html_elements(selector_list) |> html_text2() # fail
page |> html_element('tr:not(td ~ td)') # fail
page |> html_element('tr:not(td)') # pass
現在,看一下湯篩,這是 Beautiful Soup 4 使用的 python package ,它:
提供從 CSS 1 級規范到最新的 CSS 4 級草案及更高版本的選擇器(盡管有些尚未實施)。
截至 28/7/22
選擇器級別 4 的實現細節允許在:not() 中使用選擇器列表
import requests
from bs4 import BeautifulSoup as bs
selector = 'tr[style]:nth-child(1) ~ tr:not( tr[style]:nth-child(n+2) ~ tr):not([style]) td:first-child'
soup = bs(requests.get('https://clinicaltrials.gov/ct2/results/details?cond=breast+cancer').text, 'html.parser')
soup.select(selector)
解決方案:
一些可能的選項可能包括:
page |> html_elements(xpath = '(//tr[count(preceding-sibling::tr[@style])=1 and count(following-sibling::tr[@style])>=2])//td[1]') |> html_text(trim = T)
現在,這些是位置匹配,因此您可能決定通過使用一些涉及您的搜索詞的基於文本的匹配來改進。
在 xpath 中使用計數的想法是我從@Daniel Haley那里得到的
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.