moear_spider_zhihudaily.entry 源代码

import os
import json
import html
import tempfile
from collections import OrderedDict

from bs4 import BeautifulSoup

from moear_api_common import base
from .spiders.zhihu_daily import ZhihuDailySpider as zhihu
from .crawler_script import CrawlerScript


_base_dir = os.path.dirname(os.path.abspath(__file__))
_assets_dir = os.path.join(_base_dir, 'assets')
_images_path = os.path.join(_assets_dir, 'images')
_css_path = os.path.join(_assets_dir, 'css')


[文档]class ZhihuDaily(base.SpiderBase): ''' 知乎日报爬虫插件 '''
[文档] def hook_custom_options(self): ''' 该方法返回当前类的自定义配置项,由基类在 ``__init__`` 方法中调用, 调用点位于,Common默认全局配置完成后,用户元数据配置前 :return: 返回当前类的自定义配置项 :rtype: dict ''' return {}
[文档] def register(self, *args, **kwargs): ''' 调用方可根据主键字段进行爬虫的创建或更新操作 :return: 返回符合接口定义的字典数据 :rtype: dict ''' return { 'name': zhihu.name, 'display_name': zhihu.display_name, 'author': zhihu.author, 'email': zhihu.email, 'description': zhihu.description, 'meta': { # 爬取计划,参考 crontab 配置方法 'crawl_schedule': '0 23 * * *', # 执行爬取的随机延时,单位秒,用于避免被 Ban 'crawl_random_delay': str(60 * 60), 'package_module': 'mobi', 'language': 'zh-CN', 'book_mode': 'periodical', # 'periodical' | 'book' 'img_cover': os.path.join( _images_path, 'cv_zhihudaily.jpg'), 'img_masthead': os.path.join( _images_path, 'mh_zhihudaily.gif'), 'image_filter': json.dumps(['zhihu.com/equation']), 'css_package': os.path.join( _css_path, 'package.css') } }
[文档] def crawl(self, *args, **kwargs): ''' 执行爬取操作,并阻塞直到爬取完成,返回结果数据。 此处考虑到 Scrapy 本身的并发特性,故通过临时文件方式做数据传递, 将临时路径传递到爬虫业务中,并在爬取结束后对文件进行读取、 JSON 反序列化,返回 :return: 返回符合接口定义的字典对象 :rtype: dict ''' temp = tempfile.NamedTemporaryFile(mode='w+t') try: crawler = CrawlerScript() # 调试时可指定明确日期参数,如:date='20180423' crawler.crawl(output_file=temp.name, *args, **kwargs) temp.seek(0) content = json.loads(temp.read(), encoding='UTF-8') finally: temp.close() print('抓取完毕!') return content
[文档] def format(self, data, *args, **kwargs): ''' 将传入的Post列表数据进行格式化处理。此处传入的 ``data`` 格式即为 :meth:`.ZhihuDaily.crawl` 返回的格式,但具体内容可以不同,即此处保留了灵活度, 可以对非当日文章对象进行格式化,制作相关主题的合集书籍 :param data: 待处理的文章列表 :type data: list :return: 返回符合mobi打包需求的定制化数据结构 :rtype: dict ''' sections = OrderedDict() hot_list = [] normal_list = [] for item in data: meta = item.get('meta', []) # 如果标题为空,则迭代下一条目 if not item.get('title'): continue soup = BeautifulSoup(item.get('content'), "lxml") # 清洗文章内容,去除无用内容 for view_more in soup.select('.view-more'): view_more.extract() item['content'] = str(soup.div) # 处理文章摘要,若为空则根据正文自动生成并填充 if not item.get('excerpt') and item.get('content'): word_limit = self.options.get( 'toc_desc_word_limit', 500) content_list = soup.select('div.content') content_list = [content.get_text() for content in content_list] excerpt = ' '.join(content_list)[:word_limit] # 此处摘要信息需进行HTML转义,否则会造成toc.ncx中tag处理错误 item['excerpt'] = html.escape(excerpt) # 从item中提取出section分组 top = meta.pop('spider.zhihu_daily.top', '0') item['meta'] = meta if str(top) == '1': hot_list.append(item) else: normal_list.append(item) if hot_list: sections.setdefault('热闻', hot_list) if normal_list: sections.setdefault('日报', normal_list) return sections