ThreadExecutorPool в скребке выходит рано, не знаю, почему, поскольку синхронная версия этого кода работает нормально

#python #multithreading #web-scraping #python-requests #threadpool

Вопрос:

Я создаю скребок с использованием python и заставил его работать синхронно; затем я решил запустить его параллельно, чтобы ускорить его работу, но это, похоже, не работает, так как он завершается до завершения всех запросов. Код ниже, спасибо за любую помощь. Я использую параллельные фьючерсы для потоковой передачи. Я не уверен, что может быть причиной этой проблемы

 import time
from bs4 import BeautifulSoup
import requests
import hashlib
import json
import threading
from concurrent.futures import ThreadPoolExecutor
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0'
}
start_time = time.time()

workers = 100


def getGardenia():
    json_file = open('datasets2/Gardenia.json', 'w', encoding='utf-8')
    json_file_details = open(
        'datasets2/GardeniaDetails.json', 'w', encoding='utf-8')
    pool = ThreadPoolExecutor(max_workers=workers)

    def getMedDetails(link, name):
        document = requests.get(link, headers=headers)
        soup = BeautifulSoup(document.content, 'html.parser')
        for element in soup.find_all('div', class_='woocommerce-Tabs-panel woocommerce-Tabs-panel--description panel entry-content wc-tab'):
            obj = {hashlib.md5(name.encode()
                               ).hexdigest(): element.get_text()}
            json.dump(obj, json_file_details, ensure_ascii=False, indent=4)
            print(str(obj)[:30])

    def getMeds(page):
        URL = f'https://gardeniapharmacy.com/product-category/find-a-medicine/page/{page}/'
        document = requests.get(URL, headers=headers)
        soup = BeautifulSoup(document.content, 'html.parser')
        for element in soup.find_all('div', class_='astra-shop-summary-wrap'):
            a = element.a
            span = element.span.get_text()
            link = a.get('href')
            name = a.get_text()
            obj = {
                'name': name, 'link': link, 'category': span[1:]
            }
            json.dump(obj, json_file, ensure_ascii=False, indent=4)
            print(obj)
            pool.submit(getMedDetails, link, name)

    for page in range(1, 221):
        pool.submit(getMeds, page)
    pool.shutdown(wait=True)

    json_file.close()
    json_file_details.close()



def getEDS():
    json_file = open('datasets2/EDS.json', 'w', encoding='utf-8')
    json_file_details = open(
        'datasets2/EDSDetails.json', 'w', encoding='utf-8')
    pool = ThreadPoolExecutor(max_workers=workers)

    def generateCategoryURL():
        urls = []
        URL = f'http://egyptiandrugstore.com/index.php?route=product/categoryamp;path=59'
        document = requests.get(URL)
        soup = BeautifulSoup(document.content, 'html.parser')
        for element in soup.find_all('li', class_='accordion'):
            link = element.a.get('href')
            urls.append(link 'amp;page=1')
        return urls

    def getNumPages(URL):
        document = requests.get(URL)
        soup = BeautifulSoup(document.content, 'html.parser')
        div = soup.find('div', class_='results').text
        start = div.find('(') 1
        end = div[start:].find(' ')
        return int(div[start:start end])

    def getMedDetails(URL, name):
        document = requests.get(URL, headers=headers)
        soup = BeautifulSoup(document.content, 'html.parser')
        for element in soup.find_all('div', id='tab-description'):
            obj = {hashlib.md5(name.encode()).hexdigest(): element.get_text()}
            json.dump(obj, json_file_details, ensure_ascii=False, indent=4)
            print(str(obj)[:30])

    def getMeds(URL, page):
        document = requests.get(URL[:-1] str(page), headers=headers)
        soup = BeautifulSoup(document.content, 'html.parser')
        category = soup.find('h2', id='title-page').get_text()
        for element in soup.find_all('div', class_='name'):
            element = element.a
            link = element.get('href')
            name = element.get_text()
            obj = {'link': link, 'name': name, 'category': category[:-12]}
            pool.submit(getMedDetails, link, name)
            json.dump(obj, json_file, ensure_ascii=False, indent=4)
            print(obj)

    catUrl = generateCategoryURL()

    def startMeds(URL):
        numOfPages = getNumPages(URL) 1
        for page in range(1, numOfPages 1):
            pool.submit(getMeds, URL, page)

    for URL in catUrl:
        pool.submit(startMeds, URL)

    pool.shutdown(wait=True)

    json_file.close()
    json_file_details.close()


mainThreads = [
    threading.Thread(target=getEDS),
    threading.Thread(target=getGardenia)
]

for x in mainThreads:
    x.start()
for x in mainThreads:
    x.join()
print("time to complete: --- %s seconds ---" % (time.time() - start_time))
 

Ответ №1:

Однако приведенный выше код работает для меня!

Единственное незначительное исправление, которое я могу предложить (которое я также сделал в соответствии со своей локальной машиной).

datasets2 Папки не было, и, следовательно, либо создайте ее, либо позвольте программе выплевывать файлы только в одном и том же напрямую. В противном случае программа сломается только там.

Комментарии:

1. Вы позволили ему пройти через завершение? Если вы проверите один из файлов json, он должен быть в 37 тысяч строк. Скребок останавливается до завершения всех запросов