上一篇我们已经让代码跑起来,各个字段也能在控制台输出,但是以item类字典的形式写的代码过于冗长,且有些字段出现的结果不统一,比如发布日期。

而且后续要把数据存到数据库,目前的字段基本都是string类型,会导致占用空间较多,查询时速度会较慢,所以本篇先对目前已写好的代码进行适当优化。


本篇目的:使用item loader以及processor对代码进行优化,对字段数据进行清洗

1、修改一下items.py文件的字段

我们对工资和工作经验字段进行分割让其更适合数据库存储:

import scrapy

class LagouItem(scrapy.Item):
url = scrapy.Field()
name = scrapy.Field()
ssalary = scrapy.Field() #最低工资
esalary = scrapy.Field() #最高工资
location = scrapy.Field()
syear = scrapy.Field() #最低工作经验
eyear = scrapy.Field() #最高工作经验
edu_background = scrapy.Field()
type = scrapy.Field()
tags = scrapy.Field()
release_time = scrapy.Field()
advantage = scrapy.Field()
job_desc = scrapy.Field()
work_addr = scrapy.Field()
company = scrapy.Field()

小贴士:我们要使用item loaders,需要对其有一个基本的了解。item loaders可以看成是对item对象的一个封装,也就是说它同样可以对字段进行操作,另外对于每一个字段,都有一个input processor和一个output processor,也就是输入处理器,和输出处理器,一般情况下,output processor即输出处理器使用的更多,它可以对我们使用css或者xpath选择出的结果进行进一步的处理。


2、编写lagou_c.py文件

导入LagouCLoader以及修改parse_item()函数

   from lagou.loaders import LagouCLoader  #这个loaders.py文件是新建立的文件,它包括一个LagouCLoader类使用处理器对item进行处理

   def parse_item(self,response):
loader = LagouCLoader(item=LagouItem(),response=response)
loader.add_value('url',response.url)
loader.add_css('name','.name::text')
loader.add_css('ssalary','.salary::text')
loader.add_css('esalary','.salary::text')
loader.add_xpath('location','//*[@class="job_request"]//span[2]/text()')
loader.add_xpath('syear','//*[@class="job_request"]//span[3]/text()')
loader.add_xpath('eyear','//*[@class="job_request"]//span[3]/text()')
loader.add_xpath('edu_background','//*[@class="job_request"]//span[4]/text()')
loader.add_xpath('type','//*[@class="job_request"]//span[5]/text()')
loader.add_css('tags','.labels::text')
loader.add_css('release_time','.publish_time::text')
loader.add_css('advantage','.job-advantage p::text')
loader.add_css('job_desc','.job_bt p::text')
loader.add_xpath('work_addr','//div[@class="work_addr"]/a[1]/text()') #这个work_addr分成了三次进行填充,最终需要把得到的数据进行合并
loader.add_xpath('work_addr','//div[@class="work_addr"]/a[2]/text()')
addr_value = response.css('.work_addr::text').extract()[-2].strip()
loader.add_value('work_addr',addr_value)
loader.add_css('company','.job_company img::attr(alt)')
yield loader.load_item()

解释:可以看到我们先生成了一个LagouCLoader实例对象,这个类使用了两个参数,一个是LagouItem对象,还有一个是response对象,而下方调用了一系列的方法对字段进行填充,add_xpath,add_css,add_value就是字面上的意思,对response使用xpath,css或者直接用一个value值进行填充。这和我们之前写的parse_item()比较类似,不同的是之前的每一个字段我们都直接进行了处理。最后使用yield loader.load_item()方法将字段分配出去。


强行解释一波:

上面的解释可能大家看的还是有点懵,我就用现实生活中的例子来说吧。现在我要做3个菜,青椒肉丝,西红柿炒鸡蛋,酸辣土豆丝。

items (空字段):可以看成这三个菜,但是最开始是没有的,需要加工出来

input processor:可以看成是前置处理,洗菜,切菜,准备配料等。

add_xpath,add_css,add_value:开始炒菜咯,放点油,放点盐,多加点辣椒。。。

output processor: 可以看成是后置处理,菜做好了, 撒点葱,香油

items(成品):现在可以上菜了,yield laoder.load_item()


3、编写loaders.py文件

细心的童鞋可能发现了,我们在lagou_c.py文件中只是把字段提取了出来,但是还没有做处理,所以我们在items.py文件的同级目录下建立一个loaders.py文件

  • 首先导入loaders以及几个自带的processor处理器,Join,Compose,TakeFirst,MapCompose
 from scrapy.loader.processors import Join, Compose, TakeFirst, MapCompose
from scrapy.loader import ItemLoader

Join:和python原生库中的Join用法类似,用来做拼接

Compose:参数传入多个函数对象,这几个函数会依次调用

MapCompose:和Compose类似,不同的是它可以对一个列表中的每个值分别调用函数

TakeFirst:和extract_first()类似,不过,TakeFirst是产生第一个非空的值

  • 建立一个LagouCLoader类,它继承自ItemLoader,字段的处理在这个类下面进行
class LagouCLoader(ItemLoader):
default_output_processor = TakeFirst() #设置默认的输出处理器为TakeFirst,也就是说,所有的字段信息提取出来后,会自动取第一个值,类似extract_first()

但是我们目前还有几个字段不能这样处理

location、edu_backgroud:提取出的字段需要去掉/和多余的空格

ssalary、esalary:最低工资和最高工资在同一个字段里,需要分别拿出来

syear、eyear:最低工作年限和最高工作年限需要进一步处理,提取出的字段有类似几种情况,a:如3-5年,b.如三年以上 c.如经验不限

release_time:发布时间同样分类似几种情况,a.如 2天前 b.如13:20c.如2018-11-11

tags、advantage、job_desc:需要使用Join方法进行拼接


  • 我这里直接给出代码
from scrapy.loader.processors import Join, Compose, TakeFirst, MapCompose
from scrapy.loader import ItemLoader
import re
import datetime def change_value(value):
return value.replace('/', '').strip() #把字段的’/‘更换为空,然后把首位多余的空格去掉 def time_trans(value):
if '天前' in value: #针对字段中有几天前的情况
num = re.search('(\d+).*', value).group(1)
time_pub = datetime.datetime.now() - datetime.timedelta(days=int(num)) #获取num天前的日期
return time_pub.strftime('%Y-%m-%d')
if '-' in value: #针对字段中有-的情况,也就是有具体发布日期的情况
time_pub = re.search('(\d+-\d+-\d+).*', value).group(1)
return time_pub
else:
return datetime.datetime.now().strftime('%Y-%m-%d') #把当前日期转为string格式 def exp_trans(value):
if '-' in value: #针对有具体工作经验年限要求的
result = re.findall('(\d+).*-(\d+).*', value)
elif '以上' in value: #针对含多少年以上工作经验的情况
result = re.search('(\d+).*', value)
else:
result = [(0, 0)] #和另外两种情况保持一致格式
return result #返回的结果是一个列表(内含元组),元组内第一个是最低工作年限,第二个值是最高工作年限 class LagouCLoader(ItemLoader):
default_output_processor = TakeFirst() #将所有的字段都进行后处理,只取第一个非空值,但是要注意这个优先级是低于_in,_out的
location_out = Compose(TakeFirst(), change_value) #字段名+_out代表的就是对输出后的处理
edu_background_out = Compose(TakeFirst(), change_value)
ssalary_out = Compose(TakeFirst(), lambda x: re.search('(\d+).*-(\d+).*', x).group(1))
esalary_out = Compose(TakeFirst(), lambda x: re.search('(\d+).*-(\d+).*', x).group(2))
syear_out = Compose(TakeFirst(), exp_trans, lambda x: x[0][0])
eyear_out = Compose(TakeFirst(), exp_trans, lambda x: x[0][1])
release_time_out = Compose(TakeFirst(), time_trans)
tags_out = Compose(Join(','))
advantage_out = Compose(Join(','))
job_desc_out = Compose(Join('\n'))
work_addr_out = Compose(Join(''))

小贴士:

  • default_output_processor = TakeFirst(),设置所有的默认输出处理器都使用TakeFirst(),这样对于所有的字段全都只会取第一个非空值,针对数据本身就很整齐,不需要额外进行清洗的,这种操作收益最大。
  • 如果需要对某个字段使用输入处理器,可以使用字段名+_in = processor()来对该字段进行输入的修饰处理,注意这里的processor是指Compose、TakeFirst等。比如字段名是name,name_in = Compose(lambda x:x.strip())就可以对输入进行处理了,处理的结果就是输入的值前后去除了多余的空格。同理,如果要对某个字段使用输出处理器,那就使用字段名+_out来进行操作。
  • 优先级说明:类似_in,_out这种操作,优先级是高于default_output_processor(或者default_input_processor)优先级的,所以如果对某个字段采取了_in,_out操作,这个操作就会把default_output_processor的操作给覆盖掉。

这样我们就完成了前期的代码优化,运行下程序看下结果,可以看到符合我们的预期要求。

scrapy抓取拉勾网职位信息(五)——代码优化的更多相关文章

  1. scrapy抓取拉勾网职位信息(一)——scrapy初识及lagou爬虫项目建立

    本次以scrapy抓取拉勾网职位信息作为scrapy学习的一个实战演练 python版本:3.7.1 框架:scrapy(pip直接安装可能会报错,如果是vc++环境不满足,建议直接安装一个visua ...

  2. scrapy抓取拉勾网职位信息(三)——爬虫rules内容编写

    在上篇中,分析了拉勾网需要跟进的页面url,本篇开始进行代码编写. 在编写代码前,需要对scrapy的数据流走向有一个大致的认识,如果不是很清楚的话建议先看下:scrapy数据流 本篇目标:让拉勾网爬 ...

  3. scrapy抓取拉勾网职位信息(二)——拉勾网页面分析

    网站结构分析: 四个大标签:首页.公司.校园.言职 我们最终是要得到详情页的信息,但是从首页的很多链接都能进入到一个详情页,我们需要对这些标签一个个分析,分析出哪些链接我们需要跟进. 首先是四个大标签 ...

  4. scrapy抓取拉勾网职位信息(四)——对字段进行提取

    上一篇中已经分析了详情页的url规则,并且对items.py文件进行了编写,定义了我们需要提取的字段,本篇将具体的items字段提取出来 这里主要是涉及到选择器的一些用法,如果不是很熟,可以参考:sc ...

  5. scrapy抓取拉勾网职位信息(八)——使用scrapyd对爬虫进行部署

    上篇我们实现了分布式爬取,本篇来说下爬虫的部署. 分析:我们上节实现的分布式爬虫,需要把爬虫打包,上传到每个远程主机,然后解压后执行爬虫程序.这样做运行爬虫也可以,只不过如果以后爬虫有修改,需要重新修 ...

  6. scrapy抓取拉勾网职位信息(七)——数据存储(MongoDB,Mysql,本地CSV)

    上一篇完成了随机UA和随机代理的设置,让爬虫能更稳定的运行,本篇将爬取好的数据进行存储,包括本地文件,关系型数据库(以Mysql为例),非关系型数据库(以MongoDB为例). 实际上我们在编写爬虫r ...

  7. scrapy抓取拉勾网职位信息(七)——实现分布式

    上篇我们实现了数据的存储,包括把数据存储到MongoDB,Mysql以及本地文件,本篇说下分布式. 我们目前实现的是一个单机爬虫,也就是只在一个机器上运行,想象一下,如果同时有多台机器同时运行这个爬虫 ...

  8. scrapy抓取拉勾网职位信息(六)——反爬应对(随机UA,随机代理)

    上篇已经对数据进行了清洗,本篇对反爬虫做一些应对措施,主要包括随机UserAgent.随机代理. 一.随机UA 分析:构建随机UA可以采用以下两种方法 我们可以选择很多UserAgent,形成一个列表 ...

  9. 【图文详解】scrapy爬虫与动态页面——爬取拉勾网职位信息(2)

    上次挖了一个坑,今天终于填上了,还记得之前我们做的拉勾爬虫吗?那时我们实现了一页的爬取,今天让我们再接再厉,实现多页爬取,顺便实现职位和公司的关键词搜索功能. 之前的内容就不再介绍了,不熟悉的请一定要 ...

随机推荐

  1. Ibatis的resultMap和查询数据的对应关系

    iBatis和MyBatis 中返回数据对应关系 直接进入主题,现在的项目改用MyBatis了,感觉跟iBatis还是不一样的,比如在判断空值上面,iBatis是有标签的<isNotEmpty& ...

  2. PowderDesign的使用

    (一)PowderDesign的安装 powderDesign下面简称pd,安装的话在网上找到安装包,安装后破解就行了.打开如图: (二)sql导入 操作步骤:File----------->R ...

  3. 1.java内存区域与内存溢出异常

    1.java运行时数据区如图所示: 2.每个区域的功能 (1)程序计数器(寄存器) 当前线程所执行的字节码的行号指示器 为了线程切换后能够恢复到正确的执行位置,因此每个线程拥有自己独立的程序计数器 如 ...

  4. POJ 2431 优先队列

    汽车每过一单位消耗一单位油,其中有给定加油站可加油,问到达终点加油的最小次数. 做法很多的题,其中优先对列解这题是很经典的想法,枚举每个加油站,判断下当前油量是否小于0,小于0就在前面挑最大几个直至油 ...

  5. python列表排序方法reverse、sort、sorted

    python语言中的列表排序方法有三个:reverse反转/倒序排序.sort正序排序.sorted可以获取排序后的列表.在更高级列表排序中,后两中方法还可以加入条件参数进行排序. reverse() ...

  6. 桥接模式_NAT模式_仅主机模式_模型图.ziw

      2017年1月12日, 星期四 桥接模式_NAT模式_仅主机模式_模型图   null

  7. 关于NuGet

    一.NuGet是什么? NuGet是Microsoft开发平台的程序集包管理器,它由客户端工具和服务端站点组成,客户端工具提供给用户管理和安装/卸载软件程序包,以及打包和发布程序包到NuGet服务端站 ...

  8. 移动端meta声明

    <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --><html lang="zh-cmn-Hans"> ...

  9. Sublime之快捷键(二)

    1. 在使用Sublime的时候,经常用到选中文件中相同的一些字段,那怎么办呢? 快捷键: ctrl + d 可以快速的选择,你所选中的文字,每次按下该快捷键,就会自动的寻找相同的字段: Alt + ...

  10. 爬虫实战--基于requests 和 Beautiful的7160美图网爬取图片

    import requests import os from bs4 import BeautifulSoup import re # 初始地址 all_url = 'http://www.7160. ...