刮擦表并将行写入CSV

时间:2012-11-26 21:03:17

标签: python performance

我正在开发一个项目,该项目在每个20条记录的表格中搜集大约400,000条记录。目前,我的脚本为页面创建了一个完整的URL列表,然后为每个URL打开页面,找到包含BeautifulSoup的表,并擦除每一行。在刮擦每一行时,它会将行写入CSV:

def scrape_table(url):
    soup = get_soup(url)
    table = soup.find('table' , {'id' : 'BigTable'})
    for row in table.find_all('tr'):
        cells = row.find_all('td')
        if len(cells) > 0:
            name_bits = cells[0].get_text().strip().split(',')
            first_name = name_bits[0].strip()
            last_name = name_bits[1].strip()
            species = cells[1].get_text().strip()
            bunch = re.sub(u'[\xa0\xc2\s]+',' ',str(cells[5]),flags=re.UNICODE).strip()
            bunch_strings = list(BeautifulSoup(bunch).td.strings)
            weight = bunch_strings[1].strip()
            bunch_match = re.match("dob:(.*) Mother: \$(.*)",bunch_strings[2].strip())
            dob = date_format(bunch_match.groups()[0].strip())
            mother = bunch_match.groups()[1].strip()            
            row_of_data = {
                'first_name': first_name,
                'last_name' : last_name,
                'species'   : species,
                'weight'    : weight,
                'dob'       : dob,
                'mother'    : mother
            }
            data_order = ['first_name', 'last_name', 'dob', 'mother', 'weight', 'kesavan']
                csv_row(row_of_data,data_order,'elephants')
        else:
            continue

def csv_row(data,fieldorder,filename, base=__base__):
    full_path = __base__+filename+'.csv'    
    print "writing", full_path
    with open(full_path, 'a+') as csvfile:
        linewriter = csv.DictWriter(csvfile, fieldorder, delimiter='|',
                                quotechar='"', quoting=csv.QUOTE_MINIMAL)
        linewriter.writerow(data)

我想知道如果我将每页结果写入CSV而不是写每一行,这会更有效。或者是否会使用更多内存并减慢计算机的其余部分?其他方法可以提高效率吗?

1 个答案:

答案 0 :(得分:1)

with open(full_path, 'a+') as csvfile:
    linewriter = csv.DictWriter(csvfile, fieldorder, delimiter='|',
                            quotechar='"', quoting=csv.QUOTE_MINIMAL)
    linewriter.writerow(data)

是性能杀手。它必须构造文件名,打开文件,构造一个对象,将数据写入磁盘并再次关闭文件每一行。这意味着它必须至少执行三次系统调用并等待磁盘驱动程序/控制器发出“文件已关闭并成功刷新”的信号。

您应该尝试的是至少在整个过程中保持文件处于打开状态。其内存成本可以忽略不计。所以,

def scrape_table(url, linewriter):
    # do scraping to get data
    linewriter.writerow(data)

打电话
with open(full_path, 'a+') as csvfile:
    linewriter = csv.DictWriter(csvfile, fieldorder, delimiter='|',
                            quotechar='"', quoting=csv.QUOTE_MINIMAL)

    for url in a_bunch_of_urls:
        scrape_table(url, linewriter)

通常,使用更多RAM并不会减慢任何速度。缓存结果在RAM而不是重新计算它们可能是 最常用的优化技术。