Итерирование по списку [] занимает, а для создания dict используется только первый элемент списка - PullRequest
0 голосов
/ 04 мая 2020

Я использую Python и Selenium для очистки данных со страницы HTML. Я выбираю элемент <ul>, который имеет несколько дочерних элементов <li>, которые содержат данные, которые я хочу. Но когда итерация по List[WebElement] и составление dict основаны на .text значении <div> s путем запроса элемента с .find_element_by_xpath(), я получаю только значение .text первого div.

Я удалил код python и код HTML, насколько смог:

<html>
<head>
</head>
<body>
    <ul id="listUl">
        <li id="item1">
            <div>
                <div class="content">
                    <div class="titel">
                        <div class="item_titel">Hello World</div>
                    </div>      
                    <div class="key">
                        <div class="item_key">HELLO_WORLD</div>
                    </div>
                </div>
            </div>
        </li>
        <li id="item2">
            <div>
                <div class="content">
                    <div class="titel">
                        <div class="item_titel">Merry Christmas</div>
                    </div>      
                    <div class="key">
                        <div class="item_key">MERRY_CHRISTMAS</div>
                    </div>
                </div>
            <div>
        </li>                                                       
    </ul>
</body>

from typing import List
from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement

path: str = "file:///C:/Users/<username>/Desktop/main3.html"
list_block = "//ul[@id='listUl']"
list_elements = "//li"

driver = webdriver.Firefox()
driver.get(path)

def get_data(list_item: WebElement) -> dict:
    return {
        'id': list_item.find_element_by_xpath("//div[@class='item_key']").text,
        'titel': list_item.find_element_by_xpath("//div[@class='item_titel']").text
    }

block_we: WebElement = driver.find_element_by_xpath(list_block)
result: List[dict] = []
block: WebElement = block_we
li_list: List[WebElement] = block.find_elements_by_xpath(list_elements)
for item in li_list:
    result.append(get_data(item))

print(result)   #[{'id': 'HELLO_WORLD', 'titel': 'Hello World'}, {'id': 'HELLO_WORLD', 'titel': 'Hello World'}]

Я нашел это ТАК сообщение: Заполнение словаря python для l oop возвращает те же значения , поэтому я подумал, что Мэйби не хватает, чтобы создать новый dict, и первая запись всегда используется повторно. поэтому я сделал отдельную переменную для каждой записи:

item1 = {   # item1: {'id': 'HELLO_WORLD', 'titel': 'Hello World'}
    'id': li_list[0].find_element_by_xpath("//div[@class='item_key']").text,
    'titel': li_list[0].find_element_by_xpath("//div[@class='item_titel']").text
}
item1_text = li_list[0].text    #item1_text: 'Hello World\nHELLO_WORLD'
item2 = {   # item2: {'id': 'HELLO_WORLD', 'titel': 'Hello World'}
    'id': li_list[1].find_element_by_xpath("//div[@class='item_key']").text,
    'titel': li_list[1].find_element_by_xpath("//div[@class='item_titel']").text
}
item2_text = li_list[1].text    # item2_text: 'Merry Christmas\nMERRY_CHRISTMAS

Может кто-нибудь сказать мне, какую ошибку я делаю?

РЕДАКТИРОВАТЬ: Чтобы убедиться, что Xpath не ошибается, я изменил относительные //div[@class='item_key'] и //div[@class='item_titel'] к абсолютным значениям //div/div/div[1]/div и //div/div/div[2]/div и добавление свойства html к результату get_data:

def get_data(list_item: WebElement) -> dict:
return {
    'id': list_item.find_element_by_xpath("//div/div/div[1]/div").text,
    # 'id': list_item.find_element_by_xpath("//div[@class='item_key']").text,
    'titel': list_item.find_element_by_xpath("//div/div/div[2]/div").text,
    # 'titel': list_item.find_element_by_xpath("//div[@class='item_titel']").text,
    'text': list_item.text,
    'html': list_item.get_attribute("innerHTML").replace('\t', '').replace('\n', '')
}

Вывод:

[
    {
        'id': 'Hello World', 
        'titel': 'HELLO_WORLD', 
        'text': 'Hello World\nHELLO_WORLD', 
        'html': '<div><div class="content"><div class="titel"><div class="item_titel">Hello World</div></div><div class="key"><div class="item_key">HELLO_WORLD</div></div></div></div>'
    }, 
    {
        'id': 'Hello World', 
        'titel': 'HELLO_WORLD', 
        'text': 'Merry Christmas\nMERRY_CHRISTMAS', 'html': '<div><div class="content"><div class="titel"><div class="item_titel">Merry Christmas</div></div><div class="key"><div class="item_key">MERRY_CHRISTMAS</div></div></div></div>'
    }
]

Но, тем не менее, если в моем List[WebElements] содержится более 1 <li> элемента, запросы через .find_element_by_xpath("//div/div/div[1]/div") и .find_element_by_xpath("//div/div/div[2]/div") возвращаются только для элемента 0. Даже если я вызываю функцию get_data с помощью block.find_elements_by_xpath(list_elements)[0] или block.find_elements_by_xpath(list_elements)[1] или просто с индексом 1, .find_element_by_xpath() с абсолютным или относительным xpath просто возвращает значения для первого элемента.

При изменении файла HTML таким образом, чтобы в нем оставалась только вторая <li>, функция .find_element_by_xpath() возвращает титр и ключ для (ранее) второго, теперь первого элемента. При размещении (ранее) первого элемента после второго элемента (переключении) обоих элементов, результат get_data теперь переворачивается (id и titel show element # 1 and ony # 1)

1 Ответ

1 голос
/ 04 мая 2020

Решено.

Проблема заключалась в том, что я забыл добавить . к запросу XPath в функции get_data(). Этот пост SO описывает ту же проблему: Повторяющиеся элементы получают повторяющийся результат на Selenium Python

Если я не добавлю ., XPath будет искать сверху DOM и вернуть всегда один и тот же товар.

Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...