搜尋

首頁  >  問答  >  主體

python指定生成器迭代的位置开始

一个爬虫程序需要断点恢复的功能, 之前把循环位置作为[a, b, c]保存在json当中

每次进程启动后先从json读取历史位置然后继续遍历

但因为想改成多线程版本, 就试着换成生成器

但这样一来, 每次进程退出重启, 迭代不能记忆位置了

有何良策?

爬去的网页url格式如

-init-page-line

所以我开始是这样的三层循环, (我在学校C/C++为主...我知道这个很不pythonic)


while self.index[0] <= self.limit[0]:
    while self.index[1] <= self.limit[1]:
        while self.index[2] <= self.limit[1]:
           # get page and download someting

里面的index是一个包含历史位置的列表, 每次程序开始会从一个JSON文件读取
然后每次完成一个页面的读取后就会把当前位置更新到JSON文件

因为整体的页面爬取的量十分大, 页面请求次数在千万次级别
目前IO等待占了90%以上的时间, 就像把它改成多线程的
当然也是第一次尝试多线程..

自己的思路是这样的, 首先类维护一个生成器

# 这里的范围是根据网站本身设的
self.generator = ([i, p, l, r]
                    for i in xrange(1, 27)
                    for p in xrange(1, 101)
                    for l in xrange(1, 101)

然后, 比如说JSON里读进来的历史位置, 是一个这样的列表

[5, 5, 5, 5]

再然后.. 思路有点乱了
但应该是每次在发出请求报并等待响应包的时候, 就继续去取得下一个url并发包
尽可能做到并发..

PHP中文网PHP中文网2767 天前631

全部回覆(2)我來回復

  • 阿神

    阿神2017-04-18 09:20:18

    不是很理解你想表達什麼,但是迭代器可以用這個方法指定開始位置:

    from itertools import islice
    for x in islice(iterms, 3, None)        # 这里跳过了前面3个元素

    回覆
    0
  • PHPz

    PHPz2017-04-18 09:20:18

    我還是不太懂你的意思, 不過我大概猜一下, 有任何猜錯再麻煩你跟我說。

    我猜你要爬這種形式的 url:

    -init-page-line

    所以你有三個 list 可能長這樣:

    self.lst[0] = ['init', 'a', 'b', 'end']
    self.lst[1] = ['page', 'paragraph', 'row']
    self.lst[2] = ['line', 'face', 'point']

    然後你分別有 indexlimit 來紀錄現在走到哪個位置和每個 lst 的最大 index:

    self.index = [0, 0, 0]  # in the begining
    self.limit = [3, 2, 2]

    然後你透過組合, 組出所有 url:

    while self.index[0] <= self.limit[0]:
        while self.index[1] <= self.limit[1]:
            while self.index[2] <= self.limit[2]: # P.S. 你這裡是不是打錯了
                 name1 = self.lst[0][self.index[0]]
                 name2 = self.lst[1][self.index[1]]
                 name3 = self.lst[2][self.index[2]]
                 # get page "-name1-name2-name3" and download someting
                 # update self.index

    上述是我個人猜測, 如果是要完成這件事我建議你這樣做:

    from itertools import product, dropwhile
    
    def gen_url(self):
        return '-' + '-'.join(product(*self.lst))
    
    for i, url in enumerate(gen_url())
        # get page by url and downloading something
        # if you want to stop, save i+1 to your json as a save point s
    
    # next time you conitnue the task, just load s from json as start point
    for i, url in dropwhile(lambda t: t[0]<s enumerate(gen_url()):
        # get page by url and downloading something

    • itertools.product

    • itertools.dropwhile


    我回答過的問題: Python-QA

    回覆
    0
  • 取消回覆