def start_requests(self): """ 爬虫默认接口,启动方法 :return: """ # 获取爬取时传过来的参数 # start_time: 开始时间 # end_time: 结束时间 # start_page: 开始页 (优先于start_time) # end_page: 结束页 (优先于end_time) # stop_item: 连续遇到[stop_item]个重复条目后,退出本次爬取 # spider_name: 指定的spider_name,如果不指定,使用self.name # command example: # py -3 -m scrapy crawl base_spider -a start_time="2019:01:01" -a end_time="2019:01:02" # python3 -m scrapy crawl bjggzyjy_spider -a start_time="now" -a end_time="now" # py -3 -m scrapy crawl base_spider -a start_time="now" -a end_time="now" -a start_page="700" -a end_page="1000" -a stop_item="10000" assert self.start_time is not None assert self.end_time is not None self.crawl_mode = CrawlMode.REAL_TIME if str(self.start_time).lower() == 'now' else CrawlMode.HISTORY if self.crawl_mode == CrawlMode.HISTORY: if (len(self.start_time) != 10 or len(self.end_time) != 10 or self.start_time[4] != ':' or self.end_time[4] != ':'): logging.error('Bad date format start_time:[{}] end_time:[{}]. Example: 2019:01:01'.format( self.start_time, self.end_time)) return else: # 取当天日期 _dt = datetime.fromtimestamp(time.time()) self.start_time = _dt.strftime("%Y:%m:%d") self.end_time = self.start_time # 初始化self.crawl_helper self.init_crawl_helper() # 主要配置项 _source_info = { # 页面的key,保证唯一 'page_1': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '工程建设', 'tos_code': '01', 'notice_type': '招标计划', 'notice_type_code': '0101', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxgcjszbjh', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_2': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '工程建设', 'tos_code': '01', 'notice_type': '招标公告', 'notice_type_code': '0101', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxggjtbyqs', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_3': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '工程建设', 'tos_code': '01', 'notice_type': '中标候选人公示', 'notice_type_code': '0104', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxzbhxrgs', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_4': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '工程建设', 'tos_code': '01', 'notice_type': '中标结果', 'notice_type_code': '0104', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxzbgg', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_5': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '政府采购', 'tos_code': '02', 'notice_type': '采购公告', 'notice_type_code': '0101', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxcggg', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_6': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '政府采购', 'tos_code': '02', 'notice_type': '更正事项', 'notice_type_code': '0204', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxgzsx', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_7': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '政府采购', 'tos_code': '02', 'notice_type': '成交结果公示', 'notice_type_code': '0202', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxzbjggg', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_8': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '土地使用权', 'tos_code': '03', 'notice_type': '招拍挂公告', 'notice_type_code': '0301', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxzpggg', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_9': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '土地使用权', 'tos_code': '03', 'notice_type': '招拍挂结果公示', 'notice_type_code': '0302', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxzpgjggs', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_10': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '国有产权', 'tos_code': '05', 'notice_type': '挂牌披露信息', 'notice_type_code': '0501', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxswzcgpplxx', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_11': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '国有产权', 'tos_code': '05', 'notice_type': '交易结果', 'notice_type_code': '0502', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxswzcjyjg', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_12': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '软件信息服务', 'tos_code': '90', 'notice_type': '招标公告', 'notice_type_code': '9001', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxrjxxzbgg', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_13': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '软件信息服务', 'tos_code': '90', 'notice_type': '中标候选人公示', 'notice_type_code': '9002', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxrjxxzbhx', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, 'page_14': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '北京公共资源交易网', # list页面的base地址 'base_url': 'https://ggzyfw.beijing.gov.cn/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath 'xpath_of_list': '//ul[@class="article-list2"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '软件信息服务', 'tos_code': '90', 'notice_type': '中标结果', 'notice_type_code': '9002', 'source': '北京公共资源交易网', 'site_name': '北京公共资源交易网', 'area_code': '11', 'content_code': '1', 'bid_sort': 'jyxxrjxxjyjg', 'industryName': '', 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, } logging.info('start crawling...') # 轮询每个类别 for _k, _v in _source_info.items(): # 仅爬取指定类型 if 'type' in self.__dict__ and self.type != _k: continue # 填充爬取的基本信息 self.crawl_helper.init_crawl_info(_k, _v) # 假定每个类别有不超过100000个页面 for _page_num in range(1000000): # 如果有start_page项,忽略之前的页面 if 'start_page' in self.__dict__ and _page_num < int(self.start_page) - 1: continue # 如果有end_page项 if 'end_page' in self.__dict__ and _page_num > int(self.end_page) + 1: break # 轮询公告中的不同list页面 if self.crawl_helper.get_stop_flag(_k): break # 根据获得下一页的函数,得到下一页的URL _ext_param = { 'time_type': _v['time_type'], 'bid_sort': _v['bid_sort'], 'start_time': self.start_time, 'end_time': self.end_time, } _request_url = _v['get_next_page_url'](page_index=_page_num, base_url=_v['base_url'], ext_param=_ext_param) # 生成request _request = scrapy.Request(_request_url, callback=_v['callback']) # 使用proxy _request.meta['proxy'] = JyScrapyUtil.get_http_proxy() _request.meta['max_retry_times'] = 5 logging.info('Use proxy[] to generate scrapy request'.format(_request.meta['proxy'])) # 如果需要js渲染,需要使用下面的函数 # _request = SplashRequest(_request_url, callback=_v['callback'], args={'wait': 2}) # 填充必要的参数 _request.meta['param'] = _v _request.meta['crawl_key'] = _k _request.meta['page_index'] = _page_num + 1 yield _request # 单个类别的爬取结束 self.crawl_helper.stop_crawl_info(_k) logging.info('stop crawling...')
def start_requests(self): """ 爬虫默认接口,启动方法 :return: """ # 获取爬取时传过来的参数 # start_time: 开始时间 # end_time: 结束时间 # start_page: 开始页 (优先于start_time) # end_page: 结束页 (优先于end_time) # stop_item: 连续遇到[stop_item]个重复条目后,退出本次爬取 # spider_name: 指定的spider_name,如果不指定,使用self.name # command example: # py -3 -m scrapy crawl base_spider -a start_time="2019:01:01" -a end_time="2019:01:02" # py -3 -m scrapy crawl base_spider -a start_time="now" -a end_time="now" # python3 -m scrapy crawl southern_power_spider -a start_time="now" -a end_time="now" # py -3 -m scrapy crawl base_spider -a start_time="now" -a end_time="now" -a start_page="700" -a end_page="1000" -a stop_item="10000" assert self.start_time is not None assert self.end_time is not None self.crawl_mode = CrawlMode.REAL_TIME if str(self.start_time).lower() == 'now' else CrawlMode.HISTORY if self.crawl_mode == CrawlMode.HISTORY: if (len(self.start_time) != 10 or len(self.end_time) != 10 or self.start_time[4] != ':' or self.end_time[4] != ':'): logging.error('Bad date format start_time:[{}] end_time:[{}]. Example: 2019:01:01'.format( self.start_time, self.end_time)) return else: # 取当天日期 _dt = datetime.fromtimestamp(time.time()) self.start_time = _dt.strftime("%Y:%m:%d") self.end_time = self.start_time # 初始化self.crawl_helper self.init_crawl_helper() # 主要配置项 _source_info = { # 页面的key,保证唯一 'zbgg_search': { # 通常会被填充在'source'字段里,有时也可以放在'tos' 'name': '南方电网招标', # list页面的base地址 'base_url': 'http://www.bidding.csg.cn/zbgg/', # list页面的call_back处理函数 'callback': self.parse_list_page_common, # 得到下一页url的函数,返回值一定是一个url 'get_next_page_url': self.get_normal_next_page_url, # 网站中该页面的最大页数,(可选配置,仅为优化程序执行效率,可不填) 'stop_page_num': 7000000, # 连续遇到[stop_dup_item_num]个重复条目后,停止本次抓取 # 提示:在程序运行初始阶段,此值可以设的较大,以便爬取所有的历史记录 'stop_dup_item_num': 500000 if self.crawl_mode == CrawlMode.HISTORY else 60, # list页面中,获得条目列表的xpath # 'xpath_of_list': '//ul[@class="vT-srch-result-list-bid"]/li', 'xpath_of_list': '//div[@class="BorderEEE NoBorderTop List1 Black14 Padding5"]/li', # 获得每一个条目链接地址的xpath 'xpath_of_detail_url': './a/@href', # 对每一个条目进行解析,返回CommonRawItem的类,需要实现 'item_parse_class': BaseItemCommonParser, # 其它信息,可以辅助生成CommonRawItem的字段 # 参考函数parse_list_page_common() 中 item_parser.get_common_raw_item()代码 'tos': '企业采购', 'source': '招标公告', # 'bid_sort': 1, 'time_type': 6 if self.crawl_mode == CrawlMode.HISTORY else 0, }, } logging.info('start crawling...') # 轮询每个类别 for _k, _v in _source_info.items(): # 仅爬取指定类型 if 'type' in self.__dict__ and self.type != _k: continue # 填充爬取的基本信息 print(_k) print(_v) self.crawl_helper.init_crawl_info(_k, _v) # 假定每个类别有不超过100000个页面 for _page_num in range(1000000): # 如果有start_page项,忽略之前的页面 if 'start_page' in self.__dict__ and _page_num < int(self.start_page) - 1: continue # 如果有end_page项 if 'end_page' in self.__dict__ and _page_num > int(self.end_page) + 1: break # 轮询公告中的不同list页面 if self.crawl_helper.get_stop_flag(_k): break # 根据获得下一页的函数,得到下一页的URL _ext_param = { 'time_type': _v['time_type'], # 'bid_sort': _v['bid_sort'], 'start_time': self.start_time, 'end_time': self.end_time, } _request_url = _v['get_next_page_url'](page_index=_page_num, base_url=_v['base_url'], ext_param=_ext_param) # 生成request _request = scrapy.Request(_request_url, callback=_v['callback']) # 使用proxy _request.meta['proxy'] = JyScrapyUtil.get_http_proxy() _request.meta['max_retry_times'] = 5 logging.info('Use proxy[] to generate scrapy request'.format(_request.meta['proxy'])) # 如果需要js渲染,需要使用下面的函数 # _request = SplashRequest(_request_url, callback=_v['callback'], args={'wait': 2}) # 填充必要的参数 _request.meta['param'] = _v _request.meta['crawl_key'] = _k _request.meta['page_index'] = _page_num + 1 yield _request # 单个类别的爬取结束 self.crawl_helper.stop_crawl_info(_k) logging.info('stop crawling...')