如何从CSV读取行以在多个线程中使用

时间:2018-09-20 22:40:45

标签: java multithreading selenium

假设我有一个CSV文件,其中有数百行带有两个随机关键字作为我想在Google搜索的单元格,并且第一个结果在页面上打印到控制台或存储在某个数组中。在此示例的情况下,我想我可以使用以下类似内容一次成功地读取一行:

CSVReader reader = new CSVReader(new FileReader(FILE_PATH));
String [] nextLine;
while ((nextLine = reader.readNext())) !=null) {
driver.get("http://google.com/");
driver.findElement(By.name("q").click();
driver.findElement(By.name("q").clear();
driver.findElement(By.name("q").sendKeys(nextLine[0] + " " + nextLine[1]);
System.out.println(driver.findElement(By.xpath(XPATH_TO_1ST));
}

我该如何通过硒处理5个或更多线程的chromedriver,以便尽快处理CSV文件?我能够一次在执行Runnable的类上执行5条线并启动5个线程,但是我想知道是否存在一种解决方案,即一旦一个线程完成,它将处理下一个线程可用或未处理的行,而不是等待5个搜索处理,然后继续进行下5行。将不胜感激任何建议阅读或破解的提示!

3 个答案:

答案 0 :(得分:2)

这是纯Java响应,而不是硒响应。

您要对数据进行分区。可以通过从CSV文件中读取一行并将其放入队列来制作粗略但有效的分区程序。然后,运行尽可能多的线程来简单地将下一个条目从队列中拉出并进行处理。

答案 1 :(得分:1)

如果您想同时执行5个(或更多)线程,则需要启动5个WebDriver实例,因为它不是线程安全的。至于更新CSV,您需要将每个线程的写入同步化,以防止损坏文件本身,或者您可以按一定阈值批量更新,并一次写入多行。

查看此Can Selenium use multi threading in one browser?

更新

这个怎么样?这样可以确保不在线程之间重复使用Web驱动程序。

CSVReader reader = new CSVReader(new FileReader(FILE_PATH));

// number to do at same time
int concurrencyCount = 5;
ExecutorService executorService = Executors.newFixedThreadPool(concurrencyCount);
CompletionService<Boolean> completionService = new ExecutorCompletionService<Boolean>(executorService);
String[] nextLine;

// ensure we use a distinct WebDriver instance per thread
final LinkedBlockingQueue<WebDriver> webDrivers = new LinkedBlockingQueue<WebDriver>();
for (int i=0; i<concurrencyCount; i++) {
    webDrivers.offer(new ChromeDriver());
}
int count = 0;
while ((nextLine = reader.readNext()) != null) {
    final String [] line = nextLine;
    completionService.submit(new Callable<Boolean>() {
        public Boolean call() {
            try {
                // take a webdriver from the queue to use
                final WebDriver driver = webDrivers.take();
                driver.get("http://google.com/");
                driver.findElement(By.name("q")).click();
                driver.findElement(By.name("q")).clear();
                driver.findElement(By.name("q")).sendKeys(line[0] + " " + line[1]);
                System.out.println(line[1]);
                line[2] = driver.findElement(By.xpath(XPATH_TO_1ST)).getText();

                // put webdriver back on the queue
                webDrivers.offer(driver);
                return true;
            } catch (InterruptedException e) {
                e.printStackTrace();
                return false;
            }
        }
    });
    count++;
}

boolean errors = false;
while(count-- > 0) {
    Future<Boolean> resultFuture = completionService.take();
    try {
        Boolean result = resultFuture.get();
    } catch(Exception e) {
        e.printStackTrace();
        errors = true;
    }
}
System.out.println("done, errors=" + errors);
for (WebDriver webDriver : webDrivers) {
    webDriver.close();
}
executorService.shutdown();

答案 2 :(得分:0)

您可以为每一行创建Callable并将其分配给ExecutorService。它负责任务的执行并为您管理工作线程。仔细选择线程池大小以获得最佳执行时间。

有关线程池大小的更多信息,请参见here