# Scrapy Tencent **Repository Path**: sice5921/Scrapy-Tencent ## Basic Information - **Project Name**: Scrapy Tencent - **Description**: 传智播客视频的学习笔记,其中涉及到的网站数据,仅为测试。 - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-05-15 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Scrapy 项目步骤 - Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。 - Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。 - Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理, - Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器), - Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方. - Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。 - Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests) **Scrapy的运作流程:** 1. 引擎:spider, 你要处理哪一个网站? 2. Spider:引擎我要处理xxxx.com。 3. 引擎:你把第一个需要处理的URL给我吧。 4. Spider:第一个URL是xxxxxxx.com。 5. 引擎:调度器,我这有request请求你帮我排序入队一下。 6. 调度器:好的,正在处理你等一下。 7. 引擎:调度器,把你处理好的request请求给我。 8. 调度器:给你,这是我处理好的request 9. 引擎:下载器,帮我下载一下这个request请求 10. 下载器:好的!给你,这是下载好的东西。(如果失败:引擎告诉调度器,这个request下载失败了,你记录一下,我们待会儿再下载) 11. 引擎:Spider,这是下载好的东西,并且下载中间件处理过了(注意!这儿responses默认是交给def parse()这个函数处理的) 12. Spider:(处理完毕数据之后对于需要跟进的URL),引擎,我这里有两个结果,这个是我需要跟进的URL,还有这个是我获取到的Item数据。 13. 引擎:管道 我这儿有个item你帮我处理一下!调度器!这是需要跟进URL你帮我处理下。然后从第四步开始循环,直到获取完需要全部信息。 14. 管道``调度器:好的,现在就做! 15. 注意!只有当调度器中不存在任何request了,整个程序才会停止,(也就是说,对于下载失败的URL,Scrapy也会重新下载。) **1、创建项目** ~~~ $ scrapy startproject xxx ~~~ **2、编写 item.py文件** ~~~ $ vim item.py #设置需要保存的数据字段 ~~~ **3、新建爬虫文件** ~~~ $ cd xx/spiders/ $ scrapy genspider spiderName "domains" #spiderName:爬虫名;domeins:域名,例如baidu.com #此时创建一个文件 spiderName.py ~~~ ~~~ [spiderName.py] # -*- coding: utf-8 -*- import scrapy from tencent.items import TencentItem class TencentpositionSpider(scrapy.Spider): name = 'tencentPosition' allowed_domains = ['tencent.com'] url="https://hr.tencent.com/position.php?&start=" offset=0 start_urls =[url+str(offset)] def parse(self, response): for each in response.xpath("//tr[@class='even'] | //tr[@class='odd']"): #初始化模型对象 item=TencentItem() #each.xpath("./td[0]/a/text()")返回的是一个SelectorList对象 #each.xpath("./td[0]/a/text()").extract()返回的是一个List #职位名 item['positionName']=each.xpath("./td[1]/a/text()").extract()[0] #详情链接 item['positionLink']=each.xpath("./td[1]/a/@href").extract()[0] #职位类别 item['positionType']=each.xpath("./td[2]/text()").extract()[0] #招聘人数 item['peopleNum']=each.xpath("./td[3]/text()").extract()[0] #工作地点 item['workLocation']=each.xpath("./td[4]/text()").extract()[0] #发布时间 item['publishTime']=each.xpath("./td[5]/text()").extract()[0] #将数据交给管道文件出库 yield(item) # 当上一页请求完成后,自增一次重新发送请求 if self.offset<990: self.offset+=10 #将请求重新发送给调度器处理:入队列,出队列,交给下载器下载 #新的请求调用scrapy.Request #scrapy.Request将url请求给调度器 #调度器将请求入队列 #出队列时将请求给下载器 #下载器发送请求到服务器返回response yield(scrapy.Request(self.url+str(self.offset),callback=self.parse)) ~~~ **提取多个子节点中的文本,并合成一个字符串。示例:** ~~~ #index.html:
123456789
~~~ ~~~ #注意xpath中的stirng(****) each.xpath("string(./td[class='index']/a[0])").extract() #输出结果 123456789 ~~~ **extract()方法说明:** ~~~ 1: item['title']=sel.xpath('//div[class='css']/text()') 2: item['title']=sel.xpath('//div[class='css']/text()').extract() 3: item['title']=sel.xpath('//div[class='css']/text()').extract()[0] 4: item['title']=sel.xpath('//div[class='css']/text()')[0].extract() 5: item['title']=sel.xpath('//div[class='css']/text()')[0].extract()[0] ~~~ (1). 返回一个SelectorList 对象 (2). 返回一个list,里面是一些你提取的内容 (3). 返回2中list的第一个元素(如果list为空抛出异常) (4). 返回1中SelectorList里的第一个元素(如果list为空抛出异常),和3达成的效果一致 (5). 返回的是一个str(如果Python2为unicode应该), 所以5会返回str的第一个字符 **4、写管道文件接收yield的数据** ~~~ $ vim pipelines.py import json class TencentPipeline(object): def __init__(self): self.filename=open("tencent.json","w") def process_item(self, item, spider): #在这里判断某个字段值为空 if len(item["positionName"])==0: return text=json.dumps(dict(item),ensure_ascii=False)+"\n" self.filename.write(text) return item #这个方法必须返回item对象,被丢弃的item将不会被之后的pipeline组件所处理 #如果不return,下次调用的是同一个item对象?? def close_spider(self,spider): self.filename.close() ~~~ **5、设置settings.py添加管道,设置请求头,下载延迟** ~~~ #管道 ITEM_PIPELINES = { 'tencent.pipelines.TencentPipeline': 300, } #请求头 DEFAULT_REQUEST_HEADERS = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0' } #下载延迟 DOWNLOAD_DELAY = 2 ~~~ **6、运行scrapy** ~~~ $ scrapy crawl tencentPosition #生成文件 $ scrapy crawl tencentPosition -o tencent.json $ scrapy crawl tencentPosition -o tencent.jsonl $ scrapy crawl tencentPosition -o tencent.csv $ scrapy crawl tencentPosition -o tencent.xml ~~~ **补充** ~~~ # 设置保存日志文件 # 在项目的settings.py文件中添加下面代码 # 保存日志信息的文件名 LOG_FILE="tencent.log" # 需要保存的日志等级 LOG_LEVEL="INFO" # 以上设置将会把tencent.log文件保存在执行目录下 ~~~