我正在使用Scrapy库抓取一个销售汽车的网站。
我正在使用Python和IBM Cloud函数以及Scrapy来实现这一目标。这个想法是每天通过IBM Cloud操作刮取该站点,并将每辆车都添加到Postgres数据库的vehicles
表中。那部分工作正常。
vehicles
表的结构如下:
第一步是将数据列以外的所有内容(这是汽车的详细信息,第二步需要添加这些内容)添加到vehicles
表中。很好。
第二步是每天检查vehicles
表中添加的每辆车是否仍在网站上(可以删除或出售)。在这一步中,我将每个循环的车辆添加到daily_run_vehicle
表中。 daily_run_vehicle
的结构如下:
如果车辆存在,我会刮擦详细信息并更新vehicles
表data
列,并将handled
表中的daily_run_vehicle
列设置为TRUE。如果已售出或删除,那么我会在retries
表的daily_run_vehicle
列中递增。
第二步应该每天运行。
首先,我循环访问vehicles
表中的handled
列为TRUE或daily_run_vehicle
为False而是{{1 }}为5以上。对于每次迭代,我都会向handled
表中添加一条新记录。
操作为retries
,代码如下:
daily_run_vehicle
prepare-get-vehicles
函数如下:
import json
import requests
from common.db import add_logs, get_vehicle_references
from common.db import capture_error
from common.common import APIHOST, NAMESPACE, USER_PASS
def execute_reference(reference, reference_url):
action = "prepare-get-vehicle"
url = APIHOST + "/api/v1/namespaces/" + NAMESPACE + "/actions/" + action
response = requests.post(url,
data=json.dumps({"reference": reference, 'reference_url': reference_url}),
params={"blocking": "false"},
auth=(USER_PASS[0], USER_PASS[1]),
headers={"Content-Type": "application/json"})
print(response.json())
def main(params):
try:
for reference in get_vehicle_references():
execute_reference(reference[0], reference[1])
return {"Success": "prepare-get-vehicles action executed successfully."}
except Exception as e:
capture_error(str(e))
return {"Failure": "prepare-get-vehicles action NOT executed successfully."}
get_vehicle_references
操作除了向def get_vehicle_references():
conn = db_connection()
cur = conn.cursor()
try:
s = "SELECT reference, reference_url FROM vehicles v WHERE (NOT EXISTS (select reference from daily_run_vehicle WHERE (handled = %s or (handled = %s and retries >= %s)) AND reference = v.reference))"
cur.execute(s, (True, False, 5))
return cur.fetchall()
except Exception as e:
capture_error(str(e))
conn.close()
表中添加新记录外,什么都不做,如下所示:
prepare-get-vehicle
但是问题在于daily_run_vehicle
表具有超过30万条记录,并且每天都在变得越来越大。与def main(params):
try:
insert_daily_run_vehicle(params.get("reference", None), params.get("reference_url", None))
return {"Success.": "The DB filler (daily_run_vehicle) is successfully executed."}
except Exception as e:
capture_error(str(e))
return {"Failure": "The DB filler (daily_run_vehicle) action NOT executed successfully."}
中的for循环相比,在IBM Cloud上执行需要花费更多时间。超时为600秒,但是for循环需要更多时间。
有什么建议可以解决我的问题,以及如何遍历具有30万条记录的表,并为每条记录向vehicles
添加新行?
谢谢。
答案 0 :(得分:0)
如果车辆的ID不变,则可以执行以下操作:
INSERT INTO vehicle (id, reference, ...etc...) VALUES (1, 'ref', ...etc...) ON CONFLICT DO NOTHING;
要插入而不在现有行上循环。您甚至可以对冲突http://www.postgresqltutorial.com/postgresql-upsert/
进行更新答案 1 :(得分:0)
要处理大型表db,您可以分批读取表行,每个批处理以编程方式运行一个新动作,每个动作可以并行运行,每个动作最多600s。
例如,如果您有一个300k的表,则以一定顺序遍历表行,例如每批100k。然后,您可以以编程方式并行调用3个动作,每个动作处理每批100k。