0

私は、それぞれ 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に書き込んだ方が効率的かどうか疑問に思っています。それとも、より多くの RAM を使用し、コンピューターの他の部分の速度が低下しますか? これをより効率的にする他の方法はありますか?

4

1 に答える 1

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

パフォーマンスキラーです。ファイル名を作成し、ファイルを開き、オブジェクトを作成し、データをディスクに書き込み、ファイルを 1 行ごとに再度閉じる必要があります。つまり、少なくとも 3 つのシステム コールを実行し、ディスク ドライバ/コントローラが「ファイルが閉じられ、正常にフラッシュされました」という信号を受け取るまで待機する必要があります。

試みるべきことは、少なくともプロセス全体を通してファイルを開いたままにすることです。そのメモリ コストはごくわずかです。そう、

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 にキャッシュすることは、おそらく最も一般的な最適化手法です。

于 2012-11-26T21:08:07.810 に答える