Я пытаюсь очистить некоторые динамические элементы с веб-страниц, используя Selenium. В конце концов, мне придется очистка страниц, исчисляемых сотнями из 1000, поэтому я пытаюсь найти способ сделать это как можно быстрее, что и привело меня к параллелизму. Я хочу записать результаты веб-скрапа в текстовый файл, но в моем коде возникают проблемы с гонкой данных. Когда я тестирую приведенный ниже код на сотне этих веб-страниц, я получаю только 60-90 из 100, записанных в файл. Я предполагаю, что это проблема гонки данных, или, может быть, я неправильно использую Selenium с параллелизмом. Ниже показано, что у меня есть до сих пор, безрезультатно пытаясь внедрить блокировки, чтобы остановить проблему гонки данных:
Текущий код указан ниже:
import time
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
import concurrent.futures
from itertools import cycle
import threading
MAX_THREADS = 10
def createDriver():
"""Creates a Selenium Chrome instance to pull JS elements"""
# Describe Chrome options
chrome_options = Options()
chrome_options.add_argument('--headless')
# Create the driver
driver = webdriver.Chrome(executable_path=r"PATH_TO_CHROMEDRIVER",
options=chrome_options, desired_capabilities=chrome_options.to_capabilities())
return driver
def getSubmitDate(ID, driver, wait, lock):
"""Function that uses a specific webdriver to get a webpage, pull the information, and write it to a file."""
# xpath for date element we want to pull
xpath = '/html/body/div[2]/div/div/form/div/div[1]/div[1]/div[1]/p/span'
# Get the webpage for the specified ID number
driver.get(f'https://232app.azurewebsites.net/Forms/ExclusionRequestItem/{ID}')
# Wait until element is visable then get it
value = wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
# Lock the write and print method with the specific lock for the wait and driver elements
# Write date to file and print out that the element has been written
with lock:
with open("date.txt", "a") as f:
f.write(value.text + '\n')
print(f'Wrote {value.text} for {ID}')
def downloadSubmitDates(IDList, driverCycles, waitCycles, lockCycles):
"""Concurrent implementation of the getSubmitDate function"""
threads = min(MAX_THREADS, len(IDList))
with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
executor.map(getSubmitDate, IDList, driverCycles, waitCycles, lockCycles)
def main():
"""Main method that executes code"""
# number of driver and lock instances
instances = 10
# Create list of ID to pull requests for
IDList = [i for i in range(10000, 10100)]
# Create list of drivers, waits, and locks to use
drivers = [createDriver() for _ in range(10)]
waits = [WebDriverWait(driver, timeout=10) for driver in drivers]
locks = [threading.Lock() for _ in range(10)]
# Create cycled version of the driver, wait, and locks
driverCycles = cycle(drivers)
waitCycles = cycle(waits)
lockCycles = cycle(locks)
# Start a time to record how long the program takes
t0 = time.time()
# Run the concurrent code
downloadSubmitDates(IDList, driverCycles, waitCycles, lockCycles)
# Close all open webdrivers
for driver in drivers:
driver.close()
# Record finish time
t1 = time.time()
print(f'{t1 - t0} seconds to download {len(IDList)}')
# Read text file to see how many records were recorded
date_df = pd.read_csv('date.txt', header=None)
print(f'Successfully pulled {date_df.shape[0]} items out of {len(IDList)}')
«Отбрасывать» означает выбрасывать, как мусор, или драться. Вероятно, вы имели в виду царапать. Отредактировано.