извлечь информацию из класса div в объект json (или фрейм данных) - PullRequest
1 голос
/ 24 марта 2020

Для каждой строки в таблице на этой странице я хотел бы щелкнуть по идентификатору (например, идентификатор строки 1 - 270516746) и извлечь / загрузить информацию (которая НЕ имеет того же самого заголовки для каждой строки) в некоторый вид объекта python, в идеале - либо объект json, либо фрейм данных (возможно, json проще).

Я дошел до того, что могу доберитесь до стола, который я хочу опустить:

import os
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import pandas as pd
import sys

driver = webdriver.Chrome()
driver.get('http://mahmi.org/explore.php?filterType=&filter=&page=1')

#find the table with ID, Sequence, Bioactivity and Similarity
element = driver.find_elements_by_css_selector('table.table-striped tr')
for row in element[1:2]: #change this, only for testing
        id,seq,bioact,sim = row.text.split()


#now i've made a list of each rows id, sequence, bioactivity and similarity.
#click on each ID to get the full data of each
        print(id)
        button = driver.find_element_by_xpath('//button[text()="270516746"]') #this is one example hard-coded
        button.click()

 #then pull down all the info to a json file?
        full_table = driver.find_element_by_xpath('.//*[@id="source-proteins"]')
        print(full_table)

И затем я застрял на том, что, вероятно, самый последний шаг, я не могу найти, как сказать '.to_ json ()' или «.to_dataframe ()» после нажатия кнопки в строке выше.

Если кто-то может посоветовать, я буду признателен.

Обновление 1: удалено и включено в выше.

Обновление 2: В дополнение к предложению ниже, чтобы использовать beautifulsoup, моя проблема заключается в том, как перейти к классу 'модальное тело' во всплывающем окне и затем использовать красивый суп:

#then pull down all the info to a json file?
        full_table = driver.find_element_by_class_name("modal-body")
        soup = BeautifulSoup(full_table,'html.parser')
        print(soup)   

возвращает ошибку:

    soup = BeautifulSoup(full_table,'html.parser')
  File "/Users/kela/anaconda/envs/selenium_scripts/lib/python3.6/site-packages/bs4/__init__.py", line 287, in __init__
    elif len(markup) <= 256 and (
TypeError: object of type 'WebElement' has no len()

Обновление 3: Затем я попытался очистить страницу, используя ТОЛЬКО beautifulsoup:

from bs4 import BeautifulSoup 
import requests

url = 'http://mahmi.org/explore.php?filterType=&filter=&page=1'
html_doc = requests.get(url).content
soup = BeautifulSoup(html_doc, 'html.parser')
container = soup.find("div", {"class": "modal-body"})
print(container)

и печатает:

<div class="modal-body">
<h4><b>Reference information</b></h4>
<p>Id: <span id="info-ref-id">XXX</span></p>
<p>Bioactivity: <span id="info-ref-bio">XXX</span></p>
<p><a id="info-ref-seq">Download sequence</a></p><br/>
<h4><b>Source proteins</b></h4>
<div id="source-proteins"></div>
</div>

Но это не тот вывод, который мне нужен, так как он не печатает слои json (например, есть дополнительная информация ниже div исходных белков).

Обновление 4, когда я добавляю к исходному коду выше (до обновлений):

full_table = driver.find_element_by_class_name("modal-body")
with open('test_outputfile.json', 'w') as output:
    json.dump(full_table, output)

Вывод: 'TypeError: Object of type' WebElement 'не JSON сериализуемый', который я сейчас пытаюсь выяснить.

Обновление 5: пытаясь скопировать этот подход, я добавил:

full_div = driver.find_element_by_css_selector('div.modal-body')
for element in full_div:
    new_element = element.find_element_by_css_selector('<li>Investigation type: metagenome</li>')
    print(new_element.text)

(где я только что добавил элемент li только для того, чтобы посмотреть, будет ли он работать), но я получаю сообщение об ошибке:

Traceback (most recent call last):
  File "scrape_mahmi.py", line 28, in <module>
    for element in full_div:
TypeError: 'WebElement' object is not iterable

Обновление 6: я пытался перебирать элементы ul / li, потому что видел это я хотел, чтобы текст li был встроен в ul в li в ul в div; поэтому я попытался:

html_list = driver.find_elements_by_tag_name('ul')
for each_ul in html_list:
       items = each_ul.find_elements_by_tag_name('li')
       for item in items:
               next_ul = item.find_elements_by_tag_name('ul')
               for each_ul in next_ul:
                       next_li = each_ul.find_elements_by_tag_name('li')
                       for each_li in next_li:
                               print(each_li.text)

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

Ответы [ 2 ]

0 голосов
/ 25 марта 2020

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

from bs4 import BeautifulSoup
import pandas as pd
import requests
from xml.etree import ElementTree as et
import xmltodict


url = "http://mahmi.org/explore.php?filterType=&filter=&page=1"
html = requests.get(url).content
df_list = pd.read_html(html)
df = df_list[-1]
headers = {
    "Connection": "keep-alive",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
}

pep_ids = df['ID'].tolist()
#pep_ids = ['270516746','268297434'] ## You can use this first to check output

base_url= 'http://mahmi.org/api/peptides/sourceProteins/'
for pep_id in pep_ids:
    final_url = base_url + str(pep_id)
    page = requests.get(final_url, headers=headers)
    tree = et.fromstring(page.content)
    for child in tree.iter('*'):
        print(child.tag,child.text)
0 голосов
/ 24 марта 2020

Вам не нужно нажимать текст с видимым. Вы можете генерировать общие c xpaths, такие как:

"(//table//td[1])//button[@data-target]"

Это обнаружит все кнопки в первом столбце таблицы. Так что вы можете go на oop.

count= len(driver.find_elements_by_xpath("(//table//td[1])//button[@data-target]"))
for i in range(count):
    driver.find_element_by_xpath("((//table//td[1])//button[@data-target])[" + str(i+1) + "]").click()
    # to get text content from pop up window 
    text = driver.find_element_by_xpath("//div[@class='modal-content']").text
    # then click close 
    driver.find_element_by_xpath("//button[text()='Close']").click()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...