pyspider的on_finished()函数调用问题

本人的需求是:在操作一批量级比较大的库时,在库中添加了一个字段----是否被读取,每条数据有唯一id标识每一条记录,所以我每次操作完100条数据,就将起是否被读取的状态置为1,之后又去取得未读取的limit 100,循环如此一直到读完整个库。但测试的时候出现了一些问题,如下

from pyspider.libs.base_handler import *
import chardet,urllib
import os,ftplib
from ftplib import FTP

class Handler(BaseHandler):
    crawl_config = {
    }
    start = 0
    
    def on_start(self):
        self.crawl('www.baidu.com', callback=self.index_page,force_update=True)

    @every(minutes=24 * 60)
    def index_page(self, response):
        for each in list(response.doc('a[href^="http"]').items())[0:1]:
            self.start += 1
            self.crawl(each.attr.href, callback=self.detail_page,force_update=True)
        ftp_connect(self.start)
        
    @config(priority=2)
    def detail_page(self, response):
        return {
            "url": response.url,
            "title": response.doc('title').text(),
        }
    
    def on_finished(self, response, task):
        #pass
        #在这里改写回显操作
        ftp_connect(self.start)
        self.on_start()
        
def ftp_connect(start):
    ftp_server = "192.168.218.10"
    username = "ftpuser"
    password = "password"
    ftp = FTP()
    ftp.set_debuglevel(0)
    ftp.connect(ftp_server,21)
    ftp.login(username,password)
    #现在本地写一个temp.text文件,将其内容读出,传到服务器的ftp路径下,再删除temp.text文件
    a = open("temp.txt","wb").write("%d"%start)
    a = open("temp.txt","rb")
    ftp.storbinary("STOR lyric.txt",a)
    os.system("rm -f temp.txt")
    return None

如上代码,我在on_finished()中进行操作时候,发现其self.start并没有按照正常的值去返回,初始化值为0,在index_page()函数中进行过 +=1 操作,本应该是1,可是最后在ftp路径下查看的文件中的值是0或1(还出现2,3...),如下图
图片描述

如上的结果,导致我在回写数据库(将是否被读取置为已读取)的时候出错,一个100条记录的任务需要执行多次才能全部置为已读取。也就是一个页面要抓取多次(大概5,6次....),暂时的解决方法是在读取完库之后立即回写,而不是在on_finished()中回写。但还是希望能了解到为什么on_finished()会出现这样的问题.

想请问下BaseHandler的运行方式,现在也正在看/pyspider/libs/base_handler.py,问题先挂出来,之后有了自己的想法再填充,希望大家能帮忙给点思路:比如class Handler(BaseHandler) 类是如何切换到task的,其中的各个def又是怎么转换成task....
先行谢谢了

阅读 4.1k
1 个回答

脚本的设计是分布式的,所以运行时不保证 Handler 只有单个实例,并且这个实例不会被重建。
所以使用 Handler 类的成员变量,它的行为是不确定的。

如果有在脚本内部保存状态的需求,我在公司项目中实现过一个类似浏览器 JS 的 localStorage 的类,它后端位于 redis 中,可以使用它在脚本间共享数据。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进