前言
掌握了一部分爬虫基础后开始学习Scrapy分布式爬虫,最初觉得会很难,以为分布式就是像hadoop分布式部署一样去配置很多文件,后来发现Scrapy相比普通python爬虫逻辑更简单,速度更快,还不容易被封IP,但是由于学的时间较短,并没有深入学习scrapy,简单记录一下爬取智联校园招聘部分数据的过程
scrapy库的安装(这部分是废话,还是自行百度吧)
安装Scrapy库时想都没想Win+R然后cmd加回车pip install scrapy,具体记不清了,反正肯定是报错了,遇到的错误和解决办法忘记了,只记得参考了N个博客后还是装上了,作为快大三的我已经习惯了把所有的雷趟一遍,所以已经习惯了,有机会从别的电脑上装一下再记录
第一个scrapy爬虫
创建scrapy项目
成功安装scrapy后,打开命令行,进入我们想存放scrapy项目的路径下
例如:F:\code
然后scrapy startproject project_name
注:project_name是自己定义的scrapy项目名称,可自行选择,也可以创建普通python项目,但结构和配置文件要自己去定义,不如自动创建的方便
如图所示创建成功
然后进入pycharm,File—>open—>找到项目所在路径并打开项目
项目路径如图所示
思路分析
这里以智联招聘的校园招聘中大数据相关职位信息作为例子
https://xiaoyuan.zhaopin.com/full/0/0_0_0_0_0_-1_%E5%A4%A7%E6%95%B0%E6%8D%AE_1_0
注:url中标红的那个1代表第一页
网页大体内容为
可以看到这里的信息比较简单,想要更详细的内容则要进入每一个职位对应的超链接中,如下图
我们要先把每个职位的超链接爬取出来然后再进入每个超链接去解析具体的内容
爬虫实现代码
items文件
作用:用scrapy.Field()方法定义我们要爬取的内容,每一条信息就是一个对象,在解析网页时赋值
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapyProjectItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 职位名称
job_name = scrapy.Field()
# 公司名称
company_name = scrapy.Field()
# 公司行业
company_industry = scrapy.Field()
# 职位类别
job_type = scrapy.Field()
# 工作地址
job_address = scrapy.Field()
# 发布日期
publish_date = scrapy.Field()
# 学历要求
edu_req = scrapy.Field()
爬虫文件
在spiders包下新建python文件,文件名自行定义
因为智联校园招聘有反爬虫机制,短时间内连续访问其网站100次IP就会被封一段时间,所以此代码中只爬取前两页,如果想爬取所有数据可以加代理池,或者用time.sleep()降低爬取频率
此处选择用xpath()进行抓取数据,bs4和正则亦可使用
import scrapy
from scrapy_project.items import ScrapyProjectItem
# 定义一个类继承scrapy.Spider
class ZhilianSpider(scrapy.Spider):
# 请求头,这里只是简单定义了user-agent
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/72.0.3626.119 Safari/537.36'
}
# 定义运行scrapy爬虫时的爬虫名称
name = 'zhilian_spider'
# 定义入口url,注意是列表
start_urls = []
for page in range(1, 3):
start_urls.append('https://xiaoyuan.zhaopin.com/full/0/0_0_0_0_0_-1_%E5%A4%A7%E6%95%B0%E6%8D%AE_{}_0'.format(str(page)))
# 重写parse函数,用此函数解析入口url页面
def parse(self, response):
# 用xpath获得所有此页面每个职位详细信息的url列表
urls_list = response.xpath('//ul[@class="searchResultListUl"]//li//p[contains(@class, "searchResultJobName") and contains(@class, "clearfix")]//a/@href').extract()
# 遍历url列表
for url in urls_list:
# 把我们得到的url提交给scrapy,callback指定用info_parse方法对每个页面进行解析
# 因为获得的url都少了'https:',所以拼接上
url = 'https:' + url
yield scrapy.Request(url, callback=self.info_parse)
# 定义info_parse方法,得到我们真正想得到的信息
def info_parse(self, response):
# 实例化我们items里面定义的类
job_info = ScrapyProjectItem()
try:
# 职位名称
job_info['job_name'] = ''.join(response.xpath('//h1[@id="JobName"]/text()').extract()[0].split())
# 公司名称
job_info['company_name'] = ''.join(response.xpath('//li[@id="jobCompany"]//a/text()').extract_first())
# 公司行业
job_info['company_industry'] = ''.join(
response.xpath('//li[@class="cJobDetailInforWd2"]/@title').extract_first())
# 职位类型
job_info['job_type'] = ''.join(response.xpath(
'//li[contains(@class, "cJobDetailInforWd2") and contains(@class, "marb")]/text()').extract()[1])
# 工作地址
job_info['job_address'] = ''.join(response.xpath(
'//li[contains(@class, "cJobDetailInforWd2") and contains(@class, "marb")]/@title').extract_first())
# 发布日期
job_info['publish_date'] = ''.join(response.xpath(
'//li[contains(@class, "cJobDetailInforWd2") and contains(@class, "marb")]/text()').extract()[3])
# 学历要求
job_info['edu_req'] = ''.join(response.xpath(
'//li[contains(@class, "cJobDetailInforWd2") and contains(@class, "marb")]/text()').extract()[5])
except Exception as e:
print(e)
yield job_info
爬虫思路:
首先重写了parse()方法爬取第一层页面所有招聘信息的url,把每个url用yield提交给scrapy.Request,让scrapy去请求该url页面,callback参数为指定解析该页面的方法,在info_parse()方法中实例化了我们在items.py文件中类的对象,并把解析出来数据对其属性进行赋值,然后yield提交给scrapy
运行scrapy
在pycharm中选中项目文件,右击选择Open in Termina
输入scrapy crawl zhilian_spider然后运行,zhilian_spider的值为继承Spider的类的name的值
运行部分结果如下
数据存储
爬出来的每一条数据以字典形式存放,可以根据scrapy crawl 命令的参数使其存储为我们想要的格式
存储为CSV格式
scrapy crawl zhilian_spider -o data.csv
存储为JSON格式
scrapy crawl zhilian_spider -o data.json
乱码解决方法
在settings.py中加入一行指定输出文件编码的语句
FEED_EXPORT_ENCODING = 'gbk'
以下为爬取的部分数据