Flask输入字段特定错误处理:限制字段合法值问题
问题
我正在开发一个爬虫网站,包含三个输入字段(第二个为可选字段)。目前当用户未填写第一个或第三个字段时,系统会显示对应的空字段错误提示;但我需要限制第三个字段仅能输入wohnung或haus,现有代码无法实现该验证——用户输入其他值时,系统仍会提示“Scraping started!”,而非像空字段那样显示错误。
现有代码
run_scraper函数
def run_scraper(city, subregion, apart_or_house): # Ask the user for input base_url = "" while True: if city != "": break else: flash("City name cannot be empty. Please enter a valid city name.", "error") return while True: if apart_or_house == "wohnung" or apart_or_house == 'haus': break elif apart_or_house == "": flash("This field cannot be empty. Please enter what are you buying.", "error") else: flash("Please enter either 'wohnung' or 'haus'.", "error") return if subregion: base_url = f"https://www.immobilienscout24.de/Suche/de/{city}/{city}/{subregion}/{apart_or_house}-kaufen" else: base_url = f"https://www.immobilienscout24.de/Suche/de/{city}/{city}/{apart_or_house}-kaufen" #Run the scraper script with the provided inputs and base_url subprocess.run(['python', 'scraper.py', city, subregion, apart_or_house, base_url]) session['scraping_finished'] = True flash('Scraper has finished!', 'info') g.scraping_finished = True
路由代码
@app.route('/scrape', methods=['GET', 'POST']) def scrape(): form = ScrapingForm() if form.validate_on_submit(): city = request.form.get('city') subregion = request.form.get('subregion') apart_or_house = request.form.get('apart_or_house') if city and apart_or_house: g.scraping_finished = False threading.Thread(target=run_scraper, args=(city, subregion, apart_or_house)).start() flash('Scraping started!', 'success') else: flash('Please fill all required fields.', 'error') if g.get('scraping_finished', False): flash('Scraper has finished!', 'info') return render_template('scrape.html', form=form)
问题原因
原代码的核心问题是校验逻辑与业务逻辑分离错误:
- 路由仅检查
city和apart_or_house非空,就直接启动爬虫线程并弹出“Scraping started!”,完全跳过了第三个字段的有效值校验。 run_scraper里的校验逻辑在线程中执行,而Flask的flash、session、g都依赖请求上下文,线程中没有这个上下文,导致校验错误无法正常显示给用户。
解决方案
把所有输入校验移到路由的请求主线程中完成,确认输入合法后再启动爬虫线程;同时简化run_scraper,只负责执行爬虫逻辑。
修改后的路由代码
@app.route('/scrape', methods=['GET', 'POST']) def scrape(): form = ScrapingForm() if form.validate_on_submit(): city = request.form.get('city').strip() subregion = request.form.get('subregion', '').strip() apart_or_house = request.form.get('apart_or_house').strip() # 统一在主线程完成所有输入校验 error_msg = None if not city: error_msg = "City name cannot be empty. Please enter a valid city name." elif not apart_or_house: error_msg = "This field cannot be empty. Please enter what are you buying." elif apart_or_house not in ('wohnung', 'haus'): error_msg = "Please enter either 'wohnung' or 'haus'." if error_msg: flash(error_msg, 'error') else: g.scraping_finished = False threading.Thread(target=run_scraper, args=(city, subregion, apart_or_house)).start() flash('Scraping started!', 'success') if g.get('scraping_finished', False): flash('Scraper has finished!', 'info') return render_template('scrape.html', form=form)
修改后的run_scraper函数
def run_scraper(city, subregion, apart_or_house): # 直接生成URL,输入已在路由校验过 base_url = (f"https://www.immobilienscout24.de/Suche/de/{city}/{city}/{subregion}/{apart_or_house}-kaufen" if subregion else f"https://www.immobilienscout24.de/Suche/de/{city}/{city}/{apart_or_house}-kaufen") # 执行爬虫脚本 subprocess.run(['python', 'scraper.py', city, subregion, apart_or_house, base_url]) # 线程中操作Flask上下文需要手动激活 with app.app_context(): session['scraping_finished'] = True g.scraping_finished = True flash('Scraper has finished!', 'info')
补充说明
- 线程中操作
session和g时,必须手动激活应用上下文(with app.app_context()),否则会抛出上下文不存在的错误。 - 如果异步任务更复杂,推荐使用
Flask-Executor或Celery这类专门的异步任务工具,比原生线程更稳定。
内容的提问来源于stack exchange,提问作者SolidOpt
相关产品推荐
相关产品推荐

