Selenium поиск статей в цикле, дающий NoSuchElementException - PullRequest
0 голосов
/ 24 сентября 2018

У меня есть простая веб-страница, содержащая список из 100 статей, которые я хочу почистить.Когда страница загружается, javascript запускается в фоновом режиме и получает список статей.Ссылка на веб-страницу: https://tools.wmflabs.org/topviews/?project=en.wikinews.org&platform=all-access&date=2016-01&excludes=Main_page

Для получения 30 лучших статей, я написал этот код.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
import numpy as np
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
import os
from time import sleep
from datetime import datetime

class WikiNewsExtraction():

def __init__(self):

    self.all_articles_name = []
    self.all_articles_links = []
    self.initial_month = '2016-01'
    self.fixed_url = 'https://tools.wmflabs.org/topviews/?\
    project=en.wikinews.org&platform=all-access&date='
    self.exclude_page = '&excludes=Main_page'
    self.id_of_first_article_name = '//*[@id="topview-entry-1"]/td[2]/div'
    self.number_of_links_extracted = 30
    self.beginning_year = 2016
    self.end_year = 2018


def setup_selenium_driver(self):

    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--window-size=1024x1400")

    # download Chrome Webdriver  
    # https://sites.google.com/a/chromium.org/chromedriver/download
    # put driver executable file in the script directory
    chrome_driver_path = os.path.join(os.getcwd(), "chromedriver")
    self.driver = webdriver.Chrome(options=chrome_options, 
    executable_path=chrome_driver_path)


def load_articles(self):


    self.all_articles_name.append('Article Name')
    self.all_articles_links.append('Article Link')

    for year in range(self.beginning_year,self.end_year+1):

        if year == self.end_year:
            end_month = datetime.today().month -1
        else:
            end_month = 12

        for month in range(1,end_month+1):

            if month<10:
                current_month = str(year)+'-0'+str(month)
            else:
                current_month = str(year)+'-'+str(month)

            url = self.fixed_url+current_month+self.exclude_page

            print('url = '+str(url))

            self.driver.get(url)
            self.driver.implicitly_wait(100)



            for index in range(self.number_of_links_extracted):

               xpath=self.id_of_first_article_name.replace('1',str(index+1))
               dom_element = self.driver.find_element_by_xpath(xpath)
                article_name = dom_element.text
                article_link = dom_element.get_attribute('href')
                self.all_articles_name.append(article_name)
                self.all_articles_links.append(article_link)


            print('Done '+str(month)+','+str(year)+'..')

    np.savetxt("Extracted_Data.csv", 
    np.column_stack((self.all_articles_name, self.all_articles_links)), 
    delimiter=",", fmt='%s')





extract = WikiNewsExtraction()
extract.setup_selenium_driver()
extract.load_articles()

При запуске выдает ошибку для xpath = // * [@ id = "topview-entry-3"] / td [2] / div, т. Е. Для третьей записи таблицы или длякакая-то другая пронумерованная запись таблицы.Принимая во внимание, что если извлечение не выполняется в цикле, и если статья извлекается напрямую через вышеуказанный xpath, она возвращает правильные данные.Я не понимаю, почему это происходит.Я пробовал более длительное время ожидания в implicit_wait (), и я пробовал driver.refresh (), но проблема по-прежнему остается

Пожалуйста, помогите.

1 Ответ

0 голосов
/ 25 сентября 2018

Если вы внимательно наблюдаете, при выполнении итерации цикла for и замене индекса ниже xpath, для 3 итераций индекс цикла for будет равен 2, поэтому он, похоже, заменит '2' в td [2], что также делает xpath устаревшим.

self.id_of_first_article_name = '//*[@id="topview-entry-1"]/td[2]/div'

Итак, используйте этот подход: присвойте номеру статьи уникальное имя, скажем: ART_ENTRY, и замените его в итерациях, как показано ниже:

self.id_of_first_article_name = '//*[@id="topview-entry-ART_ENTRY"]/td[2]/div'

Для цикла:

for index in range(self.number_of_links_extracted):
    xpath=self.id_of_first_article_name.replace('ART_ENTRY',str(index+1))
    dom_element = self.driver.find_element_by_xpath(xpath)

Пример кода, который отлично работает:

driver.implicitly_wait(5)
driver.get('https://tools.wmflabs.org/topviews/?project=en.wikinews.org&platform=all-access&date=2016-01&excludes=Main_page')
id_of_first_article_name ='//*[@id="topview-entry-ART_ENTRY"]/td[2]/div'
number_of_links_extracted = 30

for index in range(number_of_links_extracted):
    print((driver.find_element_by_xpath(id_of_first_article_name.replace('ART_ENTRY',str(index+1))).text).encode('utf-8'))
...