企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 1. Spider类 1. spider类 ~~~ # 回调parse解析 scrapy.Request(url=self.url+str(self.offset),callback=self.parse) ~~~ ~~~ # -*- coding: utf-8 -*- import scrapy from mySpider.items import tecentItem import os class TunaSpider(scrapy.Spider): name = 'tecent' # 爬虫识别名称,唯一且不同的爬虫有不一样的名字 allowed_domains = ['hr.tencent.com'] # 限制搜索域名范围 url = 'http://hr.tencent.com/position.php?&start=' offset = 0 start_urls = [url + str(offset)] # 爬虫入口url # 解析方法,每个初始URL完成下载后被调用,调用时传入每个URL的传回的 # response对象作为唯一的参数 def parse(self, response): teacher_list = response.xpath('//tr[@class="odd"]|//tr[@class="even"]') for each in teacher_list: item = tecentItem() # 不加extract() 结果为xpath匹配对象 try: position_name = each.xpath('./td[1]/a/text()').extract()[0] position_type = each.xpath('./td[2]/text()').extract()[0] # title location = each.xpath('./td[4]/text()').extract()[0] # info time = each.xpath('./td[5]/text()').extract()[0] detail = each.xpath('./td[1]/a/@href').extract()[0] print("职位名称" + position_name) print("职位:" + position_type) print("工作地点:" + location) print("发布时间" + time) print("详情:" + detail) item['position_type'] = position_type item['position_name'] = position_name item['location'] = location item['publish_time'] = time item['detail'] = "http://hr.tencent.com/" + detail yield item except: pass if self.offset < 2250: self.offset +=10 print("第几页" + self.url+str(self.offset)) else: os._exit(0) yield scrapy.Request(url=self.url+str(self.offset),callback=self.parse) ~~~ ## 2. CrawlSpider 爬虫类 ### 2.1 实例 * 建立一个CrawlSpider的爬虫子类的模板 ~~~ scrapy genspider -t crawl dongguan 'wz.sun0769.com' # scrapy genspider -t crawl 固定写法 # dongguan 'wz.sun0769.com' 爬虫名 域限定名 ~~~ 1. 这个CrawlSpider类和Spider类似,但是不一样的是,我们解析的函数一定不能是parse(),因为parse()函数此时是框架业务逻辑的实现,所以在rules上调用其他函数 ~~~ # -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from mySpider.items import dongguan class DongguanSpider(CrawlSpider): name = 'dongguan' # 爬虫标识名 allowed_domains = ['wz.sun0769.com'] # 限定爬取网页的域 # 爬虫开始页,与Spider类不同的是,它的首页值提取符合规则的连接,真正开始爬取数据从rules爬取 start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0'] # 从rlues开始提取 rules = ( # 只提取复合规则的页面链接,不做分析,所以跟页面但是没有,follow是对网易深一层的爬取,false表示不提取连接,也不请求页面上的连接 Rule(LinkExtractor(allow=r'type=4&page=\d+'), follow=True), Rule(LinkExtractor(allow=r'question/\d+/\d+\.shtml'), callback='parse_item', follow=False) ) def parse_item(self, response): item = dongguan() question = response.xpath('//div[@class="pagecenter p3"]//strong[@class="tgray14"]/text()').extract()[0] state = response.xpath('//div[@class="audit"]//span/text()').extract()[0] print("问题:" + question) print("处理状态:" + state) item['question'] = question item['state'] = state yield item ~~~ * Spider版本 处理多请求 ~~~ # -*- coding: utf-8 -*- import scrapy from newdongguan.items import NewdongguanItem class DongdongSpider(scrapy.Spider): name = 'xixi' allowed_domains = ['wz.sun0769.com'] url = 'http://wz.sun0769.com/index.php/question/questionType?type=4&page=' offset = 0 start_urls = [url + str(offset)] # parse方法用来处理页面 def parse(self, response): # 每一页里的所有帖子的链接集合 links = response.xpath('//div[@class="greyframe"]/table//td/a[@class="news14"]/@href').extract() # 迭代取出集合里的链接 for link in links: # 提取列表里每个帖子的链接,发送请求放到请求队列里,并调用self.parse_item来处理 yield scrapy.Request(link, callback = self.parse_item) # 页面终止条件成立前,会一直自增offset的值,并发送新的页面请求,调用parse方法处理 if self.offset <= 71160: self.offset += 30 # 发送请求放到请求队列里,调用self.parse处理response yield scrapy.Request(self.url + str(self.offset), callback = self.parse) # 处理每页面具体链接的 def parse_item(self, response): item = NewdongguanItem() # 标题 item['title'] = response.xpath('//div[contains(@class, "pagecenter p3")]//strong/text()').extract()[0] # 编号 item['number'] = item['title'].split(' ')[-1].split(":")[-1] # 内容,先使用有图片情况下的匹配规则,如果有内容,返回所有内容的列表集合 content = response.xpath('//div[@class="contentext"]/text()').extract() # 如果没有内容,则返回空列表,则使用无图片情况下的匹配规则 if len(content) == 0: content = response.xpath('//div[@class="c1 text14_2"]/text()').extract() item['content'] = "".join(content).strip() else: item['content'] = "".join(content).strip() # 链接 item['url'] = response.url # 交给管道 yield item ~~~ * item和pipeline都和是Spider一样,还有驱动爬虫程序开始的命令也一样 ### 2.2 LinkExtractors > class scrapy.linkextractors.LinkExtractor > Link Extractors 的目的很简单: 提取链接。 > 每个LinkExtractor有唯一的公共方法是 extract_links(),它接收一个 Response 对象,并返回一个 scrapy.link.Link 对象。 > Link Extractors要实例化一次,并且 extract_links 方法会根据不同的 response 调用多次提取链接。 ~~~ class scrapy.linkextractors.LinkExtractor( allow = (), deny = (), allow_domains = (), deny_domains = (), deny_extensions = None, restrict_xpaths = (), tags = ('a','area'), attrs = ('href'), canonicalize = True, unique = True, process_value = None ) ~~~ 主要参数: allow:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。 deny:与这个正则表达式(或正则表达式列表)不匹配的URL一定不提取。 allow_domains:会被提取的链接的domains。 deny_domains:一定不会被提取链接的domains。 restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。 ### 2.3 rules rules 在rules中包含一个或多个Rule对象,每个Rule对爬取网站的动作定义了特定操作。如果多个rule匹配了相同的链接,则根据规则在本集合中被定义的顺序,第一个会被使用。 ~~~ class scrapy.spiders.Rule( link_extractor, callback = None, cb_kwargs = None, follow = None, process_links = None, process_request = None ) ~~~ > link_extractor:是一个Link Extractor对象,用于定义需要提取的链接。 > callback: 从link_extractor中每获取到链接时,参数所指定的值作为回调函数,该回调函数接受一个response作为其第一个参数。 > 注意:当编写爬虫规则时,避免使用parse作为回调函数。由于CrawlSpider使用parse方法来实现其逻辑,如果覆盖了 parse方法,crawl spider将会运行失败。 > follow:是一个布尔(boolean)值,指定了根据该规则从response提取的链接是否需要跟进。 如果callback为None,follow 默认设置为True ,否则默认为False。 > process_links:指定该spider中哪个的函数将会被调用,从link_extractor中获取到链接列表时将会调用该函数。该方法主要用来过滤。注意:有的函数在爬虫时,可能返回虚假网址,我们需要写一个方法来修改这些虚假网址,改成正确的 > process_request:指定该spider中哪个的函数将会被调用, 该规则提取到每个request时都会调用该函数。 (用来过滤request) 例如:以下网站反爬虫把?和&调换了,所以我们要把他换回来 ~~~ class DongdongSpider(CrawlSpider): name = 'dongdong' allowed_domains = ['wz.sun0769.com'] start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page='] # 每一页的匹配规则 pagelink = LinkExtractor(allow=("type=4")) # 每一页里的每个帖子的匹配规则 contentlink = LinkExtractor(allow=(r"/html/question/\d+/\d+.shtml")) rules = ( # 本案例的url被web服务器篡改,需要调用process_links来处理提取出来的url Rule(pagelink, process_links = "deal_links"), # 没有callback ,follow默认为True Rule(contentlink, callback = "parse_item") ) # links 是当前response里提取出来的链接列表 def deal_links(self, links): for each in links: each.url = each.url.replace("?","&").replace("Type&","Type?") return links # 返回links ~~~