關於Flask框架中啓動Scrapy爬蟲框架時的幾種問題的解決

最近開發的爬蟲調度系統是由Flask框架提供接口,在Flask中啓動Scrapy項目,開發期間遇到了幾個問題,網上找找,自己也琢磨了好久,終於順利解決。問題如下:

一、Scrapy、crawl指令找不到

問題描述:

先看一下我的項目結構,如下:

hydra是Flask項目目錄,medical_illness下是Scrapy項目,handler_scrpy是接口文件。

現在要做的就是接口文件收到指令,然後啓動scrapy項目,在scrapy項目下的main_illess.py文件是啓動spider的,我在接口文件引入了這個文件,然後去運行它,就會報如上錯誤

Scrapy 1.7.1 - no active project 

Unknown command: crawl Use "scrapy" to see

解決思路:

這是因爲,在handler_scrpy中啓動main_illess.py時當前工作目錄是在Flask項目下:

D:\文檔\個人\項目\hydra

並不在scrapy項目目錄下,所以報瞭如上錯誤。在main_illess.py中做如下修改:

import os
from scrapy import cmdline
from filter.filter_change_path import set_new_path
from .disease import spiders


def start_crawl(spider_name):
    b = 'scrapy crawl '
    c = b + spider_name

    # 獲取spiders文件所在的目錄,並將工作目錄切換到spider所在目錄下
    set_new_path(os.path.dirname(spiders.__file__))

    cmdline.execute(c.split())

切換後的工作空間:

D:\文檔\個人\項目\hydra\spiders\spider_script\medical_illness\disease\disease\spiders

重點是註釋部分,獲得導入的spidres所在目錄(即scrapy所在目錄),然後見工作空間切換到scrapy目錄,然後最後一句執行爬蟲,啓動完爬蟲以後需要將工作目錄再切換回去(爲什麼要用到進程,在第二個問題中會講到):

# 啓動scrapy項目文件
def start_crawler_threads(topic_name, rules, start_url):
    # 通過start_url得到spider名字
    spider_name = get_spider(start_url)

    # 獲得當前工作目錄(根目錄)
    old_path = os.getcwd()

    # 在進程中啓動爬蟲
    crawl_threads = Process(target=main_illness.start_crawl, args=(spider_name ,))
    crawl_threads.start()

    # 啓動完線程以後交給工作目錄還原
    set_old_path(old_path)

 

set_old_path()、set_new_path()方法所在文件定義如下:

import os

"""
更改與還原工作目錄
"""


def set_new_path(path):
    os.chdir(path)


def set_old_path(path):
    os.chdir(path)

到此就解決找不到scrapy和crawl的問題了。

二、ValueError: signal only works in main thread

ERROR:tornado.application:Exception in callback (<zmq.sugar.socket.Socket object at 0x7f44c4d698d0>, <function wrap.<locals>.null_wrapper at 0x7f44c4d02378>)
Traceback (most recent call last):
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/tornado/ioloop.py", line 888, in start
    handler_func(fd_obj, events)
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/tornado/stack_context.py", line 277, in null_wrapper
    return fn(*args, **kwargs)
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py", line 450, in _handle_events
    self._handle_recv()
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py", line 480, in _handle_recv
    self._run_callback(callback, msg)
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py", line 432, in _run_callback
    callback(*args, **kwargs)
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/tornado/stack_context.py", line 277, in null_wrapper
    return fn(*args, **kwargs)
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/ipykernel/kernelbase.py", line 283, in dispatcher
    return self.dispatch_shell(stream, msg)
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/ipykernel/kernelbase.py", line 233, in dispatch_shell
    self.pre_handler_hook()
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/site-packages/ipykernel/kernelbase.py", line 248, in pre_handler_hook
    self.saved_sigint_handler = signal(SIGINT, default_int_handler)
  File "/mnt/home2/zxm/anaconda3/lib/python3.6/signal.py", line 47, in signal
    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
ValueError: signal only works in main thread

問題描述:

在我成功解決工作空間的問題之後這個問題就緊接着來了,導致以上錯誤的幾個原因,我google了一下,網上也有反映這個錯誤的,但是按照他們的方法並不能解決我的問題,於是根據這個錯誤提示,大膽猜測——

解決思路:

“signal僅適用於主線程”,是不是因爲在Flask中起動scrapy爬蟲,請求flask的接口已經佔用了主線程並且阻塞等待爬蟲運行,所以再啓動Scrapy時就會報ValueError: signal only works in main thread

根據這個思路,再啓動Scrapy時,創建一個新的進程,讓Scrapy在此進程中的主線程中運行,如下:

# 啓動scrapy項目文件
def start_crawler_threads(topic_name, rules, start_url):
    # 通過start_url得到spider名字
    spider_name = get_spider(start_url)

    # 獲得當前工作目錄(根目錄)
    old_path = os.getcwd()

    # 在進程中啓動爬蟲
    crawl_threads = Process(target=main_illness.start_crawl, args=(spider_name ,))
    crawl_threads.start()

    # 啓動完線程以後交給工作目錄還原
    set_old_path(old_path)

使用進程後,問題解決

三、subprocess.CalledProcessError: Command '['scrapy', 'crawl', 'zhkw', '-o', 'output.json']' returned non-zero exit status 2.

問題描述:

這個問題是在出現問題二之後,我採用的一個解決方法時報的錯,使用subprocess子進程啓動爬蟲,嘗試解決ValueError: signal only works in main thread

問題分析:

subprocess來啓動scrapy思路是可行的,只不過在這裏並沒有執行成功,是因爲這是在更改工作空間之前,所以會報錯。但是使用此方法會有一個缺陷,雖然再子進程中啓動了scrapy但是爬蟲依然在阻塞,接口就會一直處於阻塞狀態,所以建議使用多進程解決。

具體關於阻塞在問題四中會詳細介紹

四、接口調用爬蟲就會阻塞

問題描述:

由於本項目是由Flask提供接口來啓動爬蟲,但是爬蟲往往都是運行時間很長,接口肯定是不能一直在等待爬蟲運行完才結束

解決思路:

我們都知道進程和線程都是異步執行的,最開始我的解決辦法就是使用多線程來啓動每個爬蟲,然後啓動線程之後直接返回,爬蟲在線程中繼續運行。但是後來遇到了問題二,所以就結合問題二使用多進程來啓動爬蟲。

 

以上就是對Flask結合Scrapy中遇到的問題的解決,大家看了還有不清楚的地方,可以私信或者評論,我都會盡力解答。

另外,由於本人技術有限,此博客有何不對的地方歡迎大家指正,謝謝。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章