对于项目实战来说,那必定是需要一定的 Scrapy 的基础的,因此在编写项目之前再次推荐下 Scrapy 框架的中文官网:http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html,有需要的随时可以回去看看。。。下面我们正式开始今天的话题:使用 Scrapy 实现两种自动爬取 腾讯招聘职位 的信息 并 保存为 json 和 csv 文件格式,先稍微温故一下以下常用的命令:
创建爬虫项目:
scrapy startproject 项目名
查看当前可以使用的爬虫模板:
scrapy genspider -l
基于任意模板生成一个爬虫文件:
scrapy genspider -t 模板 自定义爬虫名 域名
执行爬虫文件(后面有:--nolog 表示不打印日记):
scrapy crawl 爬虫名 --nolog
我们打开腾讯招聘网页,并观察切换页面时候的变化以及我们需要爬取的信息字段的效果图如下:
首先我们创建一个爬虫项目,然后根据效果图在 items.py 文件中编写我们需要保存的信息字段:
import scrapy
class MytencentspiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
positionName = scrapy.Field()#职位名称
positionLink = scrapy.Field()#职位链接
positionType = scrapy.Field()#职位类别
peopleNumber = scrapy.Field()#人数
workLocation = scrapy.Field()#工作地点
publishTime = scrapy.Field()#发布时间
修改了实体文件之后,我们在观察需要提取数据的标签特点,效果图如下:
从途中可以看到,我们需要的数据都在 tr 标签中,但是细心的同学会发现,由于这些列表是斑马线的颜色,因此他们有两个不同的 class 属性类型,好了,我们现在Spisers 文件夹下创建一个基于 basic 模板的爬虫文件并处理爬取操作:
# -*- coding: utf-8 -*-
import scrapy
from MyTencentSpider.items import MytencentspiderItem
class TencentspiderSpider(scrapy.Spider):
name = 'tencentspider' #爬虫名
allowed_domains = ['tencent.com'] #指定爬取的域名
#拼接 url
myUrl = "https://hr.tencent.com/position.php?&start="
offset = 0
start_urls = [myUrl + str(offset)] #开始爬取的url
def parse(self, response):
#获取所有tr列表标签
node_list = response.xpath('//tr[@class="even"]|//tr[@class="odd"]')
#循环抓取tr标签列表里的具体数据
for node in node_list:
#创建一个容器对象用于存储每个数据
item = MytencentspiderItem()
item['positionName'] = node.xpath('./td[1]/a/text()').extract_first()
item['positionLink'] = node.xpath('./td[1]/a/@href').extract_first()
#类别有可能为空,因此需要判断一下
if len(node.xpath('./td[2]/text()')):
item['positionType'] = node.xpath('./td[2]/text()').extract_first()
else:
item['positionType'] = ""
item['peopleNumber'] = node.xpath('./td[3]/text()').extract_first()
item['workLocation'] = node.xpath('./td[4]/text()').extract_first()
item['publishTime'] = node.xpath('./td[5]/text()').extract_first()
#yield 的重要性,是返回数据后还能回来接着执行后面的代码,return 就直接结束了
yield item #将数据返回给引擎在转交管道处理
#第一种方式:拼接url 使用场景:页面没有可以点击的请求链接,必须
#通过拼接url才能获取响应
if self.offset < 400:
#重新拼接url
self.offset += 10
url = self.myUrl + str(self.offset)
#构建并发送请求给引擎再转交调度器
yield scrapy.Request(url, callback = self.parse)#回调方法处理的是请求之后的数据
接下来我们要对请求得到的数据进行操作,就要对实体管道文件进行编辑(这里实现两种保存文件的格式:json、csv):
import json
import csv
class MytencentspiderPipeline(object):
def __init__(self):#初始化
#self.f = open("tencent.json", "w", encoding="utf-8")
self.f = open("tencent.csv", "w")
self.writer = csv.writer(self.f)
self.writer.writerow(['职位名称', '职位链接', '职位类别', '人数', '工作地点', '发布时间'])
def process_item(self, item, spider):#处理
#先转换成字典然后保存为json文件
#content = json.dumps(dict(item), ensure_ascii = False) +",\n" #换行并且没有分隔符
# print("控制台输出-> "+ content)
# self.f.write(content)#写入本地
#保存为csv文件
tencent_list = [item['positionName'], item['positionLink'], item['positionType'], item['peopleNumber'],item['workLocation'], item['publishTime']]
print(tencent_list)#输出测试
self.writer.writerow(tencent_list)
return item
def close_spider(self, spider):#关闭
self.writer.close()
self.f.close()
要实现实体管道功效就必须要在 settings.py 文件中激活:
#激活管道组件
ITEM_PIPELINES = {
'MyTencentSpider.pipelines.MytencentspiderPipeline': 300,
}
为防止网站反爬,我们可以设置文件的相应配置:
#设置请求头 - 用户代理
DEFAULT_REQUEST_HEADERS = {
'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
}
#禁用 COOKIE
COOKIES_ENABLED = False
# Obey robots.txt rules 是否遵循网站协议
ROBOTSTXT_OBEY = True #建议遵循网站规则,也是尊重他人的表现
#设置下载延时
DOWNLOAD_DELAY = 0.3
万事俱备,接下来我们执行以下我们的爬虫文件(注意:执行的爬虫名字是爬虫文件里的名字而非爬虫文件名)后其中的最终效果图如下:
到目前为止项目基本完成,其实如果我们想自动爬取所有信息并且网页上有翻页按钮即“下一页”的时候,我们可以使用以下方式进行实现:
#第二种方式:直接从 response 获取需要爬取的链接并发送请求处理,直到链接全部提取完为止
if len(response.xpath('//a[@class="noactive" and @id="next"]')) == 0:
#获取“下一页”按钮的链接
url = response.xpath('//a[@id="next"]/@href').extract_first()
#构建链接并发送请求
yield scrapy.Request("https://hr.tencent.com/"+ url, callback = self.parse)