爬虫-今日头条我的收藏-增量式(二)

背景:

能够全量爬取今日头条我的收藏内容之后,新收藏的内容依然希望能够保存到新文件中。

思路:

  • 每次都全量爬取数据太耗时,增量式爬取可以节省时间。但逻辑上显然要复杂一些。关键的问题是要找到断点的位置。
  • 取消收藏的影响:爬虫旧文件用户收藏的链接有可能被取消收藏。所以在断点位置的判断上不能只取一条数据的id作为参考,考虑取连续100条的我的收藏id作为判断基准,这样即便用户偶尔取消收藏几条,依然能够准确找到断点。
  • 增量式功能可以覆盖全量下载我的收藏。第一次下载由于没有断点,需要全量下载。后续由于已经有下载的文件作为参照物,只需要从参照物继续下载。
  • 每次运行增量爬虫,如果有新内容,则新增一个文件,文件格式:myfavorites-年月日-时分秒.txt。如果没有新内容,不需要新增文件。
实现:
  • 代码参考这里:https://github.com/pmh905001/myfavorite/blob/master/toutiao/increasmentdownload.py .主代码如下:
    def increasement_download():
        url, headers = read_curl()
        latest_ids_downloaded = latest_ids_from_file()
        page = get_page(url, headers, 0, latest_ids_downloaded)
        try_num = 0
        file_name = f'myfavorites-{time.strftime("%Y%m%d-%H%M%S")}.txt'
        while page['has_more']:
            try_num += 1
            max_behot_time = page['next']['max_behot_time']
            write_page(page, file_name)
            sleep_time = random.randint(1, 10)
            print(f'-------------------------------------------page number: {try_num}, sleep {sleep_time} seconds')
            time.sleep(sleep_time)
            page = get_page(url, headers, max_behot_time, latest_ids_downloaded)
        else:
            write_page(page, file_name)

     

  • 从断点处按照有新到旧的id需要获取最多100条,这种情况下需要遍历所有myfavorites-年月日-时分秒.txt的文件且需要倒序排列,依次读取id直到100条(用户可以自己调整)。参考latest_ids_from_file()
    def latest_ids_from_file():
        ids = []
        my_favorite_files = sorted([f for f in os.listdir('.') if f.startswith('myfavorites-')], reverse=True)
        for file_name in my_favorite_files:
            with open(file_name, 'r', encoding='utf-8') as f:
                page: dict = json.loads(f.readline())
                if page.get('data'):
                    for record in page['data']:
                        if len(ids) <= 100:
                            ids.append(record['id'])
                        else:
                            return ids
        return ids

     

  •  在获取每页的数据之后,需要找到断点,把冗余的数据给删除。重置has_more=False。参考get_page()方法
    def get_page(url, headers, max_behot_time=0, latest_ids_downloaded=[]):
        url = replace_url_param(url, 'max_behot_time', max_behot_time)
        response = requests.get(url, headers=headers)
        page: dict = response.json()
        if page.get('data'):
            for index, record in enumerate(page.get('data')):
                if record['id'] in latest_ids_downloaded:
                    page['data'] = page['data'][:index]
                    page['has_more'] = False

     

  •  在写文件的时候,如果页数据收藏列表如果为空,则不写入文件。参考write_page()
    def write_page(page, file_name):
        if not page.get('data'):
            return
        with open(file_name, 'a', encoding='utf-8') as fp:
            page_info = json.dumps(page, ensure_ascii=False)
            fp.write(page_info)
            fp.write('\n')
    
        for item in page['data']:
            try:
                print(f"{item['id']}: {item['title']}   => {item['share_url']}")
            # Fixme: UnicodeEncodeError
            except UnicodeEncodeError:
                logging.exception('occurred exception when print')

     

  • 代码写的比较粗糙,还需要找时间重构。这里仅供参考
 

posted on 2023-12-19 00:15  pmh905001  阅读(34)  评论(0编辑  收藏  举报

导航