Вебскреб на selenium python очень медленный

Я новичок в парсерах. Я сделал что-то, что работает, но чтобы получить все, что мне нужно, требуются часы и часы. Я читал кое-что об использовании параллельных процессов для обработки URL-адресов, но понятия не имею, как это сделать и включить в то, что у меня уже есть. Помощь очень ценится!

Вот мой, все еще очень запутанный код. Я еще учусь :)

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC 
from selenium.common.exceptions import TimeoutException
from bs4 import BeautifulSoup
from selenium.common.exceptions import NoSuchElementException
import time
import random
import pprint
import itertools
import csv
import pandas as pd

start_url = "https://www.nationalevacaturebank.nl/vacature/zoeken?query=&location=&distance=city&limit=100&sort=relevance&filters%5BcareerLevel%5D%5B%5D=Starter&filters%5BeducationLevel%5D%5B%5D=MBO"

driver = webdriver.Firefox()
driver.set_page_load_timeout(20)
driver.get(start_url)
driver.find_element_by_xpath('//*[@id="form_save"]').click() #accepts cookies

wait = WebDriverWait(driver, random.randint(1500,3200)/1000.0)
j = random.randint(1500,3200)/1000.0
time.sleep(j)
num_jobs = int(driver.find_element_by_xpath('/html/body/div[3]/div/main/div[2]/div[3]/div/header/h2/span').text)
num_pages = int(num_jobs/102)

urls = []
list_of_links = []

for i in range(num_pages+1):
        try:


            elements = wait.until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="search-results-container"]//article/job/a')))
            for i in elements:
                list_of_links.append(i.get_attribute('href'))

            j = random.randint(1500,3200)/1000.0
            time.sleep(j) 

            if 'page=3' not in driver.current_url:
                driver.find_element_by_xpath('//html/body/div[3]/div/main/div[2]/div[3]/div/paginator/div/nav[1]/ul/li[6]/a').click()
            else:
                driver.find_element_by_xpath('//html/body/div[3]/div/main/div[2]/div[3]/div/paginator/div/nav[1]/ul/li[5]/a').click()

            url = driver.current_url
            if url not in urls:
                print(url)
                urls.append(url)

            else:
                break


        except:
            continue


set_list_of_links = list(set(list_of_links))
print(len(set_list_of_links), "results")                
driver.close()

def grouper(n, iterable):
    it = iter(iterable)
    while True:
       chunk = tuple(itertools.islice(it, n))
       if not chunk:
           return
       yield chunk

def remove_empty_lists(l):
    keep_going = True
    prev_l = l
    while keep_going:
        new_l = remover(prev_l)
        #are they identical objects?
        if new_l == prev_l:
            keep_going = False
        #set prev to new
        prev_l = new_l
    #return the result
    return new_l


def remover(l):
    newlist = []
    for i in l:
        if isinstance(i, list) and len(i) != 0:
            newlist.append(remover(i))
        if not isinstance(i, list):
            newlist.append(i)

    return newlist

vacatures = []
chunks = grouper(100, set_list_of_links)
chunk_count = 0

for chunk in chunks: 
    chunk_count +=1
    print(chunk_count)
    j = random.randint(1500,3200)/1000.0
    time.sleep(j)

    for url in chunk:

        driver = webdriver.Firefox()
        driver.set_page_load_timeout(20)

        try: 
            driver.get(url)
            driver.find_element_by_xpath('//*[@id="form_save"]').click() #accepts cookies

            vacature = []
            vacature.append(url)

            j = random.randint(1500,3200)/1000.0
            time.sleep(j)

            elements = driver.find_elements_by_tag_name('dl')
            p_elements = driver.find_elements_by_tag_name('p')
            li_elements = driver.find_elements_by_tag_name('li')

            for i in elements:
                if "Salaris:" not in i.text:
                    vacature.append(i.text)

            running_text = list()
            for p in p_elements:
                running_text.append(p.text)

            text= [''.join(running_text)]

            remove_ls = ['vacatures', 'carrièretips', 'help', 'inloggen', 'inschrijven', 'Bezoek website', 'YouTube',
                        'Over Nationale Vacaturebank', 'Werken bij de Persgroep', 'Persberichten', 'Autotrack', 'Tweakers',
                        'Tweakers Elect', 'ITBanen', 'Contact', 'Carrière Mentors', 'Veelgestelde vragen',
                         'Vacatures, stages en bijbanen', 'Bruto Netto Calculator', 'Salariswijzer', 'Direct vacature plaatsen',
                         'Kandidaten zoeken', 'Bekijk de webshop', 'Intermediair', 'Volg ons op Facebook']

            for li in li_elements:
                if li.text not in remove_ls: 
                    text.append(li.text)

            text = ''. join(text)
            vacature.append(text)

            vacatures.append(vacature)

            driver.close() 

        except TimeoutException as ex:
            isrunning = 0
            print("Exception has been thrown. " + str(ex))
            driver.close()

        except NoSuchElementException:
            continue 

Если вы хотите улучшить рабочий код, лучше разместите свой вопрос на CodeReview

Andersson 31.10.2018 13:23

Я не совсем уверен, но использование Selenium может быть причиной медленного характера этого. Selenium визуально отображает страницу и загружает все изображения, добавляет и т. д. Если вы просто используете html-данные и очищаете их, это может быть намного быстрее. Я создал, например, сценарий с requests и BeautifulSoup, и он извлекает все данные (не изображения) из Jaap примерно за 10-15 минут (более 3000 страниц). Так что Nationale Vacaturebank также должен стать возможным в разумные сроки ...

Niels Henkens 31.10.2018 13:52

@Andersson Я сделал это, но получил реакцию, что они не помогают с кодом, который не существует, то есть как выполнять параллельную обработку

Lunalight 31.10.2018 13:56
1
3
1 956
3

Ответы 3

Веб-драйвер Python Selenium не является потокобезопасным. Это означает, что ваш браузер не может правильно использовать асинхронные вызовы из нескольких потоков. Попробуйте очистить веб-сайты с помощью Запросы и BS4 + lxml. Это намного быстрее, чем Selenium. Ответ Этот может быть полезным.

Да неужели? Я думал, что для такого рода вещей обычно используется Selenium. Спасибо :)

Lunalight 31.10.2018 13:56

Нет, как я уже сказал, использование запросов и BeautifulSoup намного быстрее, потому что вы получаете только html.

Niels Henkens 31.10.2018 14:00

@Lunalight вы можете попробовать использовать веб-драйвер PhantomJS с Selenium. Это безголовый браузер, который может быть быстрее Firefox.

Rezvanov Maxim 31.10.2018 14:22

@NielsHenkens ничто не мешает проверять веб-страницу на предмет некоторых вызовов API. Но в случае, если данные генерируются с помощью JS, мы, конечно же, должны использовать браузер.

Rezvanov Maxim 31.10.2018 14:24

Но как мне перейти на следующую страницу с запросами?

Lunalight 31.10.2018 15:54

@Lunalight requests.get(url_of_next_page). Вы знаете протокол HTTP?

Rezvanov Maxim 31.10.2018 15:58

@RezvanovMaxim Я ничего не знаю, как указано в моем OP :) Я следил за учебником по веб-сканированию с селеном и подумал, что могу расширить эти знания, кодируя то, что вы видите выше.

Lunalight 31.10.2018 16:08

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

Lunalight 31.10.2018 16:13

@Lunalight для очистки этой страницы вы не должны выходить со страниц. Я просматриваю эту веб-страницу и обнаружил, что все задания возвращаются в формате JSON за один вызов API. Просто узнайте, как проверять веб-страницу с помощью браузера Chrome.

Rezvanov Maxim 31.10.2018 16:41

@RezvanovMaxim Я проверил страницу, вот как я получил имена тегов и Xpath. В остальном я не понимаю, что вы имеете в виду?

Lunalight 31.10.2018 16:43

@Lunalight я имею в виду проверить, какие запросы отправляются с этой веб-страницы. Вы должны использовать вкладку Network в инструменте проверки в браузере Chrome. Посмотрите на мой скриншот: ibb.co/eiZK50

Rezvanov Maxim 31.10.2018 16:47
  1. Вы используете Firefox, который работает медленнее, чем Chrome, почти во всех реальных приложениях.
  2. Xpath - самый медленный селектор, соответствующий идентификатору или классу. Если это невозможно, то с помощью CSS.
  3. Используйте безголовый режим и не загружайте изображения без необходимости.

Хорошо, но во второй части я использую имя тега, разве это не CSS?

Lunalight 31.10.2018 16:36

Это самый быстрый нативный подход. Но я вижу много XPath.

misantroop 31.10.2018 16:43

Вы можете использовать Scrapy, и это намного быстрее и гибче, чем что-либо еще. См. ссылка для получения дополнительной информации.

Он использует Scrapy. Вероятно, он хочет использовать Selenium для загрузки страниц на основе javascript (SPA). Это не ответ на этот вопрос.

PrashanD 24.01.2020 10:38

Другие вопросы по теме