使用线程使用beatifulsoup解析数据

时间:2018-07-03 10:36:02

标签: python multithreading beautifulsoup

我在文本文件中有成千上万个URL,现在我想从产品链接中提取标题和价格。我试图实现线程以使其更快地执行,但是似乎它无法正常工作,从而产生重复的数据并且执行脚本的时间过长。在不使用线程的情况下,脚本可以按预期工作。

这是我的代码:

import requests
from bs4 import BeautifulSoup
import csv
import lxml
import threading

def runner(fname):

  global lck
  lck.acquire()
  with open(fname, 'r') as f:
    for line in f:
      r = requests.get(line)
      soup = BeautifulSoup(r.content, 'lxml')
      try:
        title = soup.find('h1', id='itemTitle').text.trim().encode('utf-8')
        price = soup.find('span', itemprop='price').text.trim().encode('utf-8')
      except:
        price = "No price" 

      with open("Data.csv", 'a', newline='',) as file:
        writer = csv.writer(file)
        writer.writerow([title, price]) 
  lck.release()


lck = threading.Lock()
fname = "ProductLinks.txt"
threads = []
for i in range(0, 3):
  t = threading.Thread(target = runner, args = (fname, ))
  threads.append(t)
  t.start()

for t in threads:
  t.join()

有人可以指导我如何正确执行操作,以便它可以并行提取和保存数据

1 个答案:

答案 0 :(得分:2)

之所以会产生重复的结果,是因为在创建线程时,您会多次调用同一函数。

t = threading.Thread(target = runner, args = (fname, ))

执行上述行时,参数始终为fname,据我所知始终为"ProductLinks.txt"。因此,您的程序将进入runner,在那里我看到您遍历了文本的所有行。

我怀疑您要“并行化”的内容正是在文本行上循环吗?然后,您将需要编写一个函数parse_line并将其传递到线程环境中。

我还建议您将值存储在字典中,最后导出到csv,因为不确定open环境是否是线程安全的。

def parse_line(line, result_dict):
    r = requests.get(line)
    soup = BeautifulSoup(r.content, 'lxml')
    try:
        title = soup.find('h1', id='itemTitle').text.trim().encode('utf-8')
        price = soup.find('span', itemprop='price').text.trim().encode('utf-8')
        result_dict[title] = price
    except:
        result_dict['No title'] = "No price" 

现在,假设您有一个列表,其中文件中的所有行均为字符串。您可以执行以下操作

file_lines = []
with open(fname, 'r') as f:
    for line in f:
        file_lines.append(line)

然后您可以在文件中所有行的列表中使用Threading调用此函数

my_dict = {}
for input_line in file_lines:
    t = threading.Thread(target = parse_line, args = (input_line, my_dict))
    threads.append(t)
    t.start()

最后,您可以使用熊猫将字典导出到csv

import pandas as pd
pd.DataFrame(my_dict).to_csv("Data.csv")