Web使用BeautifulSoup

时间:2018-01-23 18:01:30

标签: python beautifulsoup

我正在尝试从此页面获取一些信息:https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM2437275

我特别感兴趣的是如下提取特征数据:

group_id: xxx
medicore_id: xxxxxxx
date_of_visit_sample_drawn_date: xxxxxxx
rin: xxxxxx
donor_id: xxxxx
sle_visit_designation: xxxxxxx
bold_shipment_batch: xxxxxx
rna_concentrated: xxxxxx
subject_type: xxxxxxx
等等等等。 在检查页面时,我意识到这些信息被深深地嵌套在其他更大的表中,并且没有特殊的类/ id可供我有效地解析特征信息。 我一直试图在表中寻找表,但是我发现有时并不是所有表都被读取。这就是我到目前为止所做的:

from bs4 import BeautifulSoup
import requests

source= requests.get("https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?
acc=GSM2437275").text


soup = BeautifulSoup(source, 'lxml')
table = soup.find_all('table') 
for i in table:
  print i.prettify()
print (len(table)) #22 tables

print (table[6].prettify()) #narrow down on relevant table
table = table[6]

table_subtables = table.find_all('table')
for i in table_subtables:
   print (i.prettify())

print len(table_subtables) #14 tables

tbb = table_subtables[1] 

tbb_subtable = tbb.find_all('table')
for i in tbb_subtable:
  print (i.prettify())
print len(tbb_subtable) #12 tables

tbbb = tbb_subtable[5] 

    tbbb_subtable = tbbb.find_all('table')
for i in tbbb_subtable:
  print (i.prettify())
print len(tbbb_subtable) # 6 tables
等等等等。但是,正如我一直这样做,我发现并非所有表都被读取。有人能指出我更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

您可以使用正则表达式和urllib来抓取数据,以专门删除关键字及其相应的值:

import re
import urllib 
data = str(urllib.urlopen('https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM2437275').read())
target_vals = ['group_id', 'medicore_id', 'date_of_visit_sample_drawn_date', 'rin', 'donor_id', 'sle_visit_designation', 'bold_shipment_batch', 'rna_concentrated', 'subject_type']
final_data = {i:re.findall('(?<={}:\s)\w+'.format(i), data)[0] for i in target_vals}

输出:

{
 'date_of_visit_sample_drawn_date': '2009', 
 'rna_concentrated': 'No', 
  'sle_visit_designation': 'Baseline', 
  'rin': '8', 
  'subject_type': 'Patient', 
  'donor_id': '19', 
  'bold_shipment_batch': '1', 
  'medicore_id': 'B0019V1', 
  'group_id': 'A'
}

编辑:给定多个链接,您可以为每个链接生成一个pandas数据框:

import re
import urllib
import pandas as pd
def get_data_from_links(link, target_vals=['group_id', 'medicore_id', 'date_of_visit_sample_drawn_date', 'rin', 'donor_id', 'sle_visit_designation', 'bold_shipment_batch', 'rna_concentrated', 'subject_type']):
    data = str(urllib.urlopen(link).read())
    return {i:re.findall('(?<={}:\s)\w+'.format(i), data)[0] for i in target_vals}
returned_data = get_data_from_links('https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM2437275')
df = pd.DataFrame([returned_data])

输出:

  bold_shipment_batch date_of_visit_sample_drawn_date donor_id group_id  \
  0                   1                            2009       19        A   

  medicore_id rin rna_concentrated sle_visit_designation subject_type  
      0     B0019V1   8               No              Baseline      Patient 

如果您有要从中检索数据的链接列表,则可以通过构建结果数据的嵌套字典来构建表,以传递给DataFrame.from_dict

link_lists = ['link1', 'link2', 'link3']
final_data = {i:get_data_from_links(i) for i in link_lists}
new_table = pd.DataFrame.from_dict(final_data, orient='index')

输出(假设第一个链接为'https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM2437275'):

       rin rna_concentrated date_of_visit_sample_drawn_date  \
link1   8               No                            2009   

  sle_visit_designation bold_shipment_batch group_id subject_type  \
link1              Baseline                   1        A      Patient   

  medicore_id donor_id  
link1     B0019V1       19  

答案 1 :(得分:1)

Ajax1234在他的解决方案中的表现绝对是最好的方式。但是,如果硬编码索引不是障碍,如果您希望避免使用正则表达式来实现相同的目标,那么这是您可能会想到的另一种方法:

throw new Exception($db->error);

输出:

from bs4 import BeautifulSoup
import requests

res = requests.get("https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM2437275")
soup = BeautifulSoup(res.content, 'lxml')
for items in soup.select("td[style*='justify']")[2:3]:
    data = '\n'.join([item for item in items.strings][:9])
    print(data)