Скрипт выдает ошибку, когда он запускается с использованием многопроцессорной обработки. - PullRequest
0 голосов
/ 21 ноября 2018

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

Ссылка, в которую я положил цифры isbn для заполнения результатов .

import requests
from bs4 import BeautifulSoup
from openpyxl import load_workbook

wb = load_workbook('amazon.xlsx')
ws = wb['content']

def get_info(num):
    params = {
        'url': 'search-alias=aps',
        'field-keywords': num
    }
    res = requests.get("https://www.amazon.com/s/ref=nb_sb_noss?",params=params)
    soup = BeautifulSoup(res.text,"lxml")
    itemlink = soup.select_one("a.s-access-detail-page")
    if itemlink:
        get_data(itemlink['href'])

def get_data(link):
    res = requests.get(link)
    soup = BeautifulSoup(res.text,"lxml")
    try:
        itmtitle = soup.select_one("#productTitle").get_text(strip=True)
    except AttributeError: itmtitle = "N\A"

    print(itmtitle)

    ws.cell(row=row, column=2).value = itmtitle
    wb.save("amazon.xlsx")

if __name__ == '__main__':
    for row in range(2, ws.max_row + 1):
        if ws.cell(row=row,column=1).value==None:break
        val = ws["A" + str(row)].value
        get_info(val)

Однако, когда я пытаюсь сделать то же самое, используя multiprocessing, я получаю следующую ошибку:

ws.cell(row=row, column=2).value = itmtitle
NameError: name 'row' is not defined

Для multiprocessing чтоЯ внес изменения в мой скрипт:

from multiprocessing import Pool

if __name__ == '__main__':
    isbnlist = []
    for row in range(2, ws.max_row + 1):
        if ws.cell(row=row,column=1).value==None:break
        val = ws["A" + str(row)].value
        isbnlist.append(val)

    with Pool(10) as p:
        p.map(get_info,isbnlist)
        p.terminate()
        p.join()

Мало того ISBN, с которым я пробовал:

9781584806844
9780917360664
9780134715308
9781285858265
9780986615108
9780393646399
9780134612966
9781285857589
9781453385982
9780134683461

Как я могу избавиться от этой ошибкии получить желаемые результаты, используя multiprocessing?

1 Ответ

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

Нет смысла ссылаться на глобальную переменную row в get_data(), потому что

  1. Это глобальная переменная, которая не будет разделена между всеми «потоками» в многопроцессорной обработке.Пул, потому что они на самом деле являются отдельными процессами Python, которые не разделяют глобальные переменные.

  2. Даже если они это сделали, потому что вы строите весь список ISBN перед выполнением get_info(), значениеrow всегда будет ws.max_row + 1, потому что цикл завершен.

Таким образом, вам нужно будет указать значения строк как часть данных, передаваемых во второй аргумент p.map().Но даже если бы вы сделали это, запись в электронную таблицу и сохранение ее из нескольких процессов - плохая идея из-за блокировки файлов Windows, условия гонки и т. Д. Вам лучше просто составить список заголовковс многопроцессорной обработкой, а затем выписать их один раз, когда это будет сделано, как показано ниже:

import requests
from bs4 import BeautifulSoup
from openpyxl import load_workbook
from multiprocessing import Pool


def get_info(isbn):
    params = {
        'url': 'search-alias=aps',
        'field-keywords': isbn
    }
    res = requests.get("https://www.amazon.com/s/ref=nb_sb_noss?", params=params)
    soup = BeautifulSoup(res.text, "lxml")
    itemlink = soup.select_one("a.s-access-detail-page")
    if itemlink:
        return get_data(itemlink['href'])


def get_data(link):
    res = requests.get(link)
    soup = BeautifulSoup(res.text, "lxml")
    try:
        itmtitle = soup.select_one("#productTitle").get_text(strip=True)
    except AttributeError:
        itmtitle = "N\A"

    return itmtitle


def main():
    wb = load_workbook('amazon.xlsx')
    ws = wb['content']

    isbnlist = []
    for row in range(2, ws.max_row + 1):
        if ws.cell(row=row, column=1).value is None:
            break
        val = ws["A" + str(row)].value
        isbnlist.append(val)

    with Pool(10) as p:
        titles = p.map(get_info, isbnlist)
        p.terminate()
        p.join()

    for row in range(2, ws.max_row + 1):
        ws.cell(row=row, column=2).value = titles[row - 2]

    wb.save("amazon.xlsx")


if __name__ == '__main__':
    main()
...