Не удается правильно использовать ThreadPoolExecutor, когда функция создает единственную ссылку

#python #python-3.x #web-scraping #concurrent.futures

#python #python-3.x #очистка веб-страниц #concurrent.futures

Вопрос:

Я создал скрипт с использованием библиотеки concurrent.futures для многопоточности, чтобы ускорить выполнение скрипта. Если первая функция get_content_url() в скрипте создала несколько ссылок, текущая реализация будет работать. Однако, поскольку первая функция создает единственную ссылку, я не понимаю, как использовать concurrent.futures в таких случаях.

Чтобы вы поняли, что делает первая функция — когда я передаю идентификаторы из файла csv в эту функцию get_content_url() , она генерирует единственную ссылку, используя токен, собранный из ответа json.

Как я могу concurrent.futures правильно применить в скрипте, чтобы ускорить выполнение?

Я пробовал с:

 import requests
import concurrent.futures
from bs4 import BeautifulSoup

base_link = "https://www.some_website.com/{}"
target_link = "https://www.some_website.com/{}"

def get_content_url(item_id):
    r = requests.get(base_link.format(item_id['id']))
    token = r.json()['token']
    content_url = target_link.format(token)
    yield content_url

def get_content(target_link):
    r = requests.get(target_link)
    soup = BeautifulSoup(r.text,"html.parser")
    try:
        title = soup.select_one("h1#maintitle").get_text(strip=True)
    except Exception: title = ""
    print(title)

if __name__ == '__main__':
    with open("IDS.csv","r") as f:
        reader = csv.DictReader(f)
        with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor:
            for _id in reader:
                future_to_url = {executor.submit(get_content,item): item for item in get_content_url(_id)}
                concurrent.futures.as_completed(future_to_url)
  

Ответ №1:

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

 import csv
import random

import requests
import concurrent.futures
from bs4 import BeautifulSoup

base_link = "https://www.some_website.com/{}"
target_link = "https://www.some_website.com/{}"


def get_content_url(item_id):
    url = base_link.format(item_id)
    print(f"Requesting {url}...")
    token = requests.get(url).json()['token']
    return target_link.format(token)


def get_content(item_id):
    url = get_content_url(item_id)
    print(f"Fetching {url}...")
    r = requests.get(url)
    soup = BeautifulSoup(r.text, "html.parser")
    try:
        title = soup.select_one("h1#maintitle").get_text(strip=True)
        return title
    except Exception as exc:
        return exc


def write_fake_ids():
    fake_ids = [
        {"item": "sample_item", "item_id": _} for _ in 
        random.sample(range(1000, 10001), 1000)
    ]
    with open("IDS.csv", "w") as output:
        w = csv.DictWriter(output, fieldnames=fake_ids[0].keys())
        w.writeheader()
        w.writerows(fake_ids)


def get_ids():
    with open("IDS.csv") as csv_file:
        ids = csv.DictReader(csv_file)
        yield from (id_ for id_ in ids)


if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor:
        future_to_url = {
            executor.submit(get_content, id_['item_id']): id_ for id_ in get_ids()
        }
        for future in concurrent.futures.as_completed(future_to_url):
            print(future.result())
  

Я издеваюсь над файлом .csv write_fake_ids() . Вы можете игнорировать ее или удалить, она нигде не вызывается в коде.

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

1. Хотя я еще не тестировал ваш скрипт, я полагаю, что он более или менее делает что-то подобное . Я не опубликовал это только потому, что думал, что есть лучший способ. Спасибо.