cách cải thiện tốc độ mã Webscrapping bằng python mã đa luồng

Sep 11 2020

dưới đây là mã của tôi mà tôi đang viết từng hàng (có khoảng 900 trang với 10 hàng và 5 dữ liệu trong mỗi hàng) có cách nào để làm cho việc này nhanh hơn không. Hiện tại, mất 80 phút để xuất dữ liệu sang csv. Có cách nào để thực hiện Yêu cầu song song với các trang và làm cho mã này hiệu quả hơn không.

import requests
from urllib3.exceptions import InsecureRequestWarning
import csv

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
from bs4 import BeautifulSoup as bs

f = csv.writer(open('GEM.csv', 'w', newline=''))
f.writerow(['Bidnumber', 'Items', 'Quantitiy', 'Department', 'Enddate'])


def scrap_bid_data():
    page_no = 1
    while page_no < 910:
        print('Hold on creating URL to fetch data...')
        url = 'https://bidplus.gem.gov.in/bidlists?bidlists&page_no=' + str(page_no)
        print('URL created: ' + url)
        scraped_data = requests.get(url, verify=False)
        soup_data = bs(scraped_data.text, 'lxml')
        extracted_data = soup_data.find('div', {'id': 'pagi_content'})
        if len(extracted_data) == 0:
            break
        else:
            for idx in range(len(extracted_data)):
                if (idx % 2 == 1):
                    bid_data = extracted_data.contents[idx].text.strip().split('\n')

                    bidno = bid_data[0].split(":")[-1]
                    items = bid_data[5].split(":")[-1]
                    qnty = int(bid_data[6].split(':')[1].strip())
                    dept = (bid_data[10] + bid_data[12].strip()).split(":")[-1]
                    edate = bid_data[17].split("End Date:")[-1]
                    f.writerow([bidno, items, qnty, dept, edate])

            page_no=page_no+1
scrap_bid_data()

Trả lời

2 Booboo Sep 11 2020 at 18:54

Tôi đã cấu trúc lại mã của bạn một chút để đảm bảo rằng tệp CSV của bạn đã được đóng. Tôi cũng nhận được thông báo lỗi sau:

ConnectionError: HTTPSConnectionPool (host = 'bidplus.gem.gov.in', port = 443): Đã vượt quá số lần thử lại tối đa với url: / bidlists? Bidlists & page_no = 1 (Gây ra bởi NewConnectionError ('<urllib3.connection.HTTPSConnection đối tượng tại 0x0000012EB0DF1Ection đối tượng 0x0000012 Không thể thiết lập kết nối mới: [WinError 10060] Một nỗ lực kết nối không thành công do bên được kết nối không phản hồi đúng cách sau một khoảng thời gian hoặc kết nối được thiết lập không thành công do máy chủ được kết nối không phản hồi ',))

Bạn nên thử nghiệm với NUMBER_THREADSgiá trị:

import requests
from urllib3.exceptions import InsecureRequestWarning
import csv
import concurrent.futures
import functools

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
from bs4 import BeautifulSoup as bs


def download_page(session, page_no):
    url = 'https://bidplus.gem.gov.in/bidlists?bidlists&page_no=' + str(page_no)
    print('URL created: ' + url)
    resp = session.get(url, verify=False)
    return resp.text


def scrap_bid_data():
    NUMBER_THREADS = 30 # number of concurrent download requests
    with open('GEM.csv', 'w', newline='') as out_file:
        f = csv.writer(out_file)
        f.writerow(['Bidnumber', 'Items', 'Quantitiy', 'Department', 'Enddate'])
        with requests.Session() as session:
            page_downloader = functools.partial(download_page, session)
            with concurrent.futures.ThreadPoolExecutor(max_workers=NUMBER_THREADS) as executor:
                pages = executor.map(page_downloader, range(1, 910))
                page_no = 0
                for page in pages:
                    page_no += 1
                    soup_data = bs(page, 'lxml')
                    extracted_data = soup_data.find('div', {'id': 'pagi_content'})
                    if extracted_data is None or len(extracted_data) == 0:
                        print('No data at page number', page_no)
                        print(page)
                        break
                    else:
                        for idx in range(len(extracted_data)):
                            if (idx % 2 == 1):
                                bid_data = extracted_data.contents[idx].text.strip().split('\n')

                                bidno = bid_data[0].split(":")[-1]
                                items = bid_data[5].split(":")[-1]
                                qnty = int(bid_data[6].split(':')[1].strip())
                                dept = (bid_data[10] + bid_data[12].strip()).split(":")[-1]
                                edate = bid_data[17].split("End Date:")[-1]
                                f.writerow([bidno, items, qnty, dept, edate])
scrap_bid_data()