Многопроцессорная обработка Python Selen - PullRequest
0 голосов
/ 26 ноября 2018

Я написал скрипт на python в сочетании с селеном, чтобы очистить ссылки различных постов с его целевой страницы и, наконец, получить заголовок каждого поста, отслеживая URL, ведущий к его внутренней странице.Хотя содержимое, которое я здесь проанализировал, является статическим, я использовал селен, чтобы увидеть, как он работает в многопроцессорной среде.

Тем не менее, я собираюсь выполнить очистку с помощью многопроцессорной обработки.До сих пор я знаю, что селен не поддерживает многопроцессорность, но, похоже, я ошибался.

Мой вопрос: как я могу сократить время выполнения с помощью селен, если он выполняется для многопроцессорной обработки??

This is my try (it's a working one):

import requests
from urllib.parse import urljoin
from multiprocessing.pool import ThreadPool
from bs4 import BeautifulSoup
from selenium import webdriver

def get_links(link):
  res = requests.get(link)
  soup = BeautifulSoup(res.text,"lxml")
  titles = [urljoin(url,items.get("href")) for items in soup.select(".summary .question-hyperlink")]
  return titles

def get_title(url):
  chromeOptions = webdriver.ChromeOptions()
  chromeOptions.add_argument("--headless")
  driver = webdriver.Chrome(chrome_options=chromeOptions)
  driver.get(url)
  sauce = BeautifulSoup(driver.page_source,"lxml")
  item = sauce.select_one("h1 a").text
  print(item)

if __name__ == '__main__':
  url = "https://stackoverflow.com/questions/tagged/web-scraping"
  ThreadPool(5).map(get_title,get_links(url))

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

как я могу сократить время выполнения, используя селен, если он настроен на многопроцессорную обработку

В вашем решении много времени тратится на запуск веб-драйвера для каждого URL-адреса.Вы можете сократить это время, запустив драйвер только один раз для каждого потока:

(... skipped for brevity ...)

threadLocal = threading.local()

def get_driver():
  driver = getattr(threadLocal, 'driver', None)
  if driver is None:
    chromeOptions = webdriver.ChromeOptions()
    chromeOptions.add_argument("--headless")
    driver = webdriver.Chrome(chrome_options=chromeOptions)
    setattr(threadLocal, 'driver', driver)
  return driver


def get_title(url):
  driver = get_driver()
  driver.get(url)
  (...)

(...)

В моей системе это сокращает время с 1 до 7,895 с, что составляет ~ 35% улучшения.Чтобы проверить себя, загрузите полный скрипт .

Примечание: ThreadPool использует потоки, которые ограничены Python GIL.Это нормально, если по большей части задача связана с вводом / выводом.В зависимости от последующей обработки, которую вы выполняете со соскребенными результатами, вы можете вместо этого использовать multiprocessing.Pool.Это запускает параллельные процессы, которые как группа не ограничены GIL.Остальной код остается прежним.

0 голосов
/ 28 ноября 2018

Мой вопрос: как я могу сократить время выполнения?

Selenium кажется неподходящим инструментом для просмотра веб-страниц - хотя я ценю YMMV, в частности, если вам нужно имитировать взаимодействие пользователя свеб-сайт или есть некоторые ограничения / требования JavaScript.

Для задач очистки без особого взаимодействия я получил хорошие результаты, используя пакет Python с открытым исходным кодом Scrapy для крупномасштабных задач очистки.Он выполняет многопроцессорную обработку из коробки, легко писать новые сценарии и сохранять данные в файлах или базе данных - и это действительно быстро .

Ваш скрипт выглядел бы примерно так при реализации в виде полностью параллельного паука Scrapy (обратите внимание, я не проверял это, см. документацию по селекторам ).

import scrapy
class BlogSpider(scrapy.Spider):
    name = 'blogspider'
    start_urls = ['https://stackoverflow.com/questions/tagged/web-scraping']

    def parse(self, response):
        for title in response.css('.summary .question-hyperlink'):
            yield title.get('href')

Для запуска вставьте это в blogspider.py и запустите

$ scrapy runspider blogspider.py

Полный учебник см. На веб-сайте Scrapy .

Обратите внимание, что Scrapy также поддерживает JavaScript через scrapy-splash , благодаря указателю @SIM.До сих пор я не сталкивался с этим, поэтому не могу говорить об этом, кроме того, что он хорошо интегрирован с тем, как работает Scrapy.

...