如何处理大规模的网页抓取?



情况:

我最近开始使用selenium和scrapy抓取网页,我正在做一个项目,我有一个csv文件,其中包含42000个邮政编码,我的工作是采取该邮政编码,并在这个网站上输入邮政编码和抓取所有的结果。

问题:

这里的问题是,在这样做,我必须不断点击"加载更多"按钮,直到所有的结果已经显示,只有一次已经完成,我可以收集数据。

这可能不是什么大问题,但是每个邮政编码需要2分钟,而我有42000个邮政编码。

代码:

import scrapy
from numpy.lib.npyio import load
from selenium import webdriver
from selenium.common.exceptions import ElementClickInterceptedException, ElementNotInteractableException, ElementNotSelectableException, NoSuchElementException, StaleElementReferenceException
from selenium.webdriver.common.keys import Keys
from items import CareCreditItem
from datetime import datetime
import os


from scrapy.crawler import CrawlerProcess
global pin_code
pin_code = input("enter pin code")

class CareCredit1Spider(scrapy.Spider):

name = 'care_credit_1'
start_urls = ['https://www.carecredit.com/doctor-locator/results/Any-Profession/Any-Specialty//?Sort=D&Radius=75&Page=1']

def start_requests(self):

directory = os.getcwd()
options = webdriver.ChromeOptions()
options.headless = True

options.add_experimental_option("excludeSwitches", ["enable-logging"])
path = (directory+r"\Chromedriver.exe")
driver = webdriver.Chrome(path,options=options)

#URL of the website
url = "https://www.carecredit.com/doctor-locator/results/Any-Profession/Any-Specialty/" +pin_code + "/?Sort=D&Radius=75&Page=1"
driver.maximize_window()
#opening link in the browser
driver.get(url)
driver.implicitly_wait(200)

try:
cookies = driver.find_element_by_xpath('//*[@id="onetrust-accept-btn-handler"]')
cookies.click()
except:
pass

i = 0
loadMoreButtonExists = True
while loadMoreButtonExists:
try:
load_more =  driver.find_element_by_xpath('//*[@id="next-page"]')
load_more.click()    
driver.implicitly_wait(30)
except ElementNotInteractableException:
loadMoreButtonExists = False
except ElementClickInterceptedException:
pass
except StaleElementReferenceException:
pass
except NoSuchElementException:
loadMoreButtonExists = False

try:
previous_page = driver.find_element_by_xpath('//*[@id="previous-page"]')
previous_page.click()
except:
pass

name = driver.find_elements_by_class_name('dl-result-item')
r = 1
temp_list=[]
j = 0
for element in name:
link = element.find_element_by_tag_name('a')
c = link.get_property('href')
yield scrapy.Request(c)

def parse(self, response):
item = CareCreditItem()
item['Practise_name'] = response.css('h1 ::text').get()
item['address'] = response.css('.google-maps-external ::text').get()
item['phone_no'] = response.css('.dl-detail-phone ::text').get()
yield item
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y")
dt = now.strftime("%H-%M-%S")
file_name = dt_string+"_"+dt+"zip-code"+pin_code+".csv"
process = CrawlerProcess(settings={
'FEED_URI' : file_name,
'FEED_FORMAT':'csv'
})
process.crawl(CareCredit1Spider)
process.start()
print("CSV File is Ready")

items.py


import scrapy
class CareCreditItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
Practise_name = scrapy.Field()
address = scrapy.Field()
phone_no = scrapy.Field()

:

基本上我的问题很简单。是否有一种方法来优化这段代码,以使其执行得更快?或者还有什么其他可能的方法来处理这些数据,而不需要花费很长时间?

由于站点从api动态加载数据,因此您可以直接从api检索数据。这将大大加快速度,但我仍然会执行等待以避免达到速率限制。

import requests
import time
import pandas as pd
zipcode = '00704'
radius = 75
url = f'https://www.carecredit.com/sites/ContentServer?d=&pagename=CCGetLocatorService&Zip={zipcode}&City=&State=&Lat=&Long=&Sort=D&Radius={radius}&PracticePhone=&Profession=&location={zipcode}&Page=1'
req = requests.get(url)
r = req.json()
data = r['results']
for i in range(2,r['maxPage']+1):
url = f'https://www.carecredit.com/sites/ContentServer?d=&pagename=CCGetLocatorService&Zip={zipcode}&City=&State=&Lat=&Long=&Sort=D&Radius={radius}&PracticePhone=&Profession=&location={zipcode}&Page={i}'
req = requests.get(url)
r = req.json()
data.extend(r['results'])
time.sleep(1)
df = pd.DataFrame(data)
df.to_csv(f'{pd.Timestamp.now().strftime("%d/%m/%Y_%H-%M-%S")}zip-code{zipcode}.csv')

有多种方法可以做到这一点。

1。创建一个分布式系统,在该系统中,您可以在多台机器上运行爬行器,以便并行运行。

在我看来,这是一个更好的选择,因为你还可以创建一个可扩展的动态解决方案,你将能够多次使用。

有很多方法可以做到这一点,通常它将包括将种子列表(邮政编码)划分为许多单独的种子列表,以便有单独的进程与单独的种子列表一起工作,因此下载将并行运行,例如,如果它在2台机器上运行,它将快2倍,但如果在10台机器上运行,它将快10倍,等等。

为了做到这一点,我可能会建议查看AWS,即AWS Lambda, AWS EC2实例甚至AWS Spot实例,这些是我以前使用过的,它们并不太难使用。

2。或者,如果你想在一台机器上运行它,你可以看看Python的多线程,它可以帮助你在一台机器上并行运行进程。

3。这是另一种选择,特别是如果它是一个一次性的过程。你可以尝试简单地用请求运行它,这可能会加快它的速度,但对于大量的种子,通常开发一个并行运行的进程会更快。

最新更新