写在前面:

上一篇《爬虫Scrapy框架初体验》初步介绍了Scrapy有关的理论知识和基本常用的命令,可以简单的爬取网页上大部分的内容。建议没看过的朋友们可以先点进去看一下哈学习了解一下。这篇文章就主要结合上一篇的知识来爬取“程序员客栈”https://www.proginn.com/cat/中兼职人员的简历信息。Ps:公司最近打算建立一个自己的人才库,所以需要大量的简历信息。初步想法能否从网上招聘平台来爬取一些程序员的简历信息。强调:都是合法安全依法依规能被爬取的简历信息,爬取得到简历信息不会私下进行肮脏的py交易!况且自己爬虫技术也不是特别牛逼,所以大胆往下看吧!目的主要是分析如何爬取我们需要的信息,将这些信息进行保存(导出数据库或Excel表)还有就是考虑二次爬取时怎么避免和第一次爬取得到的信息产生冲突和冗余(也就是查重增量处理)

Ps:最近在看《10x 程序员工作法》里面有说到“优秀程序员的开发效率是普通程序员的10倍”它给出了一个面对难题困难时候思考的框架。现状、目标、实现路径。说明白一点就是:我在哪?我现在水平怎样?、我要去哪里?我目标达到怎样水平?、如何去?我将怎样达到那个水平?借鉴这个思考框架也可以把我这篇文章分为三大块来介绍。为何要爬取?要爬取哪些内容?怎么爬取?以上爬取代码我已经上传到了我GitHub上(https://github.com/DayRed/Scrapy_Export_ExcelMysqlRedis),需要的朋友们可以自行下载哈。有好的建议或想法请pull request我哈!!!

为何要爬取?

上面已经大致介绍了。公司打算建立自己的人才库,需要大量程序员简历信息。通过将搜集到的信息进行机器学习提取里面的内容给这个人打上标签如Java,Python,C++,人工智能等等分门别类物以类聚人以群分,打入我们自己的人才库,方便日后操作。

……

要爬取哪些内容?

这个不用想就大致知道需要哪些内容了,例如,年龄,姓名,工作经验,就任公司,薪资…这个也没啥好过多讲的进入它的网站就知道需要什么信息了。重点是第三步怎么爬取?

怎么爬取?

https://www.proginn.com/cat/这个网站还是比较简洁清晰明了的第一眼看过去还是让你比较舒服的,不像某些网站第一看过去满眼的标题,恨不得把所有信息都一股脑儿扔向你。让你产生强烈的压抑感。

每一个兼职人员的主页信息也相当简洁清晰明了。让用户不用花太多学习时间成本。想要知道什么信息都能马上找寻到。不错,是我喜欢的style。

1.分析

  • 列表爬取

上一篇文章中介绍了如何打开爬取页面?定一个start_urls或者start_requests(self)方法的常量。刚开始我做的时候单纯把每一个人的主页地址作为爬取对象,而忽视了可以先通过获取每一页中每个兼职人员的主页链接地址作为集合再统一的传递给爬取方法进而可以遍历爬取。

start_urls = ['https://www.proginn.com/cat/']
def parse(self, response):#遍历当前页 所有人的主页链接地址cxy = response.xpath("//div[@class='user-avatar ui tiny image']//@href").extract()for i in cxy:yield scrapy.Request(url=i, callback=self.zh, dont_filter=True)  # 爬取到的页面如何处理?提交给zh方法处理

  • 全站爬取

不单单是只有当前页,还有写一页再下一页,考虑它的迭代循环爬取。

这个全站爬取,花费了我好久才做出来,之前有个“公式代码”可以方便提取但用在这里并不能完全适配。所以要定制一套但原理是同个原理。把下一页链接提交给本方法或是另一个方法,进行进一步爬取!难点就在于如何摸清它们的关系采取不同方法来调用。

总结了一下。它其实可以分为3种情况,一种是在1-9页之间。一种是10n(10的倍数页)例如第10、20、30页…还有一种是在10x-10y之间(x<y) 例如20-30 30-40 50-60…之间的。

10n倍数页的

当前页在第1-10页的

10n-10n之间 例如20-30 30-40 50-60...之间的。

no = int(response.xpath("//div[@class='ui pagination menu']//a[@class='item active']//text()").extract()[0])
if no > 9:if((no+10) % no ==0):#10的倍数页的next_page = response.xpath("//div[@class='ui pagination menu']//a//@href").extract()[2]else:#10x-10y之间的next_page = response.xpath("//div[@class='ui pagination menu']//a//@href").extract()[int(no%10+2)]
else:#<10页以下的
next_page = response.xpath("//div[@class='ui pagination menu']//a//@href").extract()[int(no)]
  • 信息切割提取

在爬取过程中,需要对一些信息进行切割提取。涉及到了python字符串、列表等操作。

例如获取当前人员目前的公司名称和公司里的级别。

#现在公司名称
user_nowcompany = response.xpath("//div[@class='introduction']//text()").extract()
if len(user_nowcompany)==2:user_nowcompany = user_nowcompany[1].split()[0]
elif len(user_nowcompany)==3:user_nowcompany = user_nowcompany[2].split()[0]
#现在公司职称
user_nowoccupation = response.xpath("//div[@class='introduction']//text()").extract()
if len(user_nowoccupation)==2:user_nowoccupation = user_nowoccupation[1].split()[1]
elif len(user_nowoccupation)==3:user_nowoccupation = user_nowoccupation[2].split()[1]

爬取毕业院校

等等……需要灵活应对页面上不同结构的提取方式。

2.保存到Excel表

上一篇文章”创建一个scrapy项目”中有讲到这4个文件是日后比较常用到的。果不其然,我们接下来就要和这几个文件打交道。GoGo.py是我们自己定义的爬虫类。名字可以不叫GoGo但是一定有这个类。

items.py是定义存储对象的文件,决定爬取哪些项目

middlewares.py文件是中间件,一般不用进行修改,主要负责相关组件之间的请求与响应

pipelines.py是管道文件,决定爬取后的数据如何进行处理和存储

settings.py是项目的设置文件,设置项目管道数据的处理方法、爬虫频率、表名等

spiders文件夹中放置的是爬虫主体文件(用于实现爬虫逻辑)和一个__init__.py空文件。

定义爬取数据对象的实体类:

pipelines.py管道文件

爬虫主体文件

项目的设置文件

scrapy crawl gogogo

3.保存到Mysql

items.py同上面的一致。需要哪些字段 自行定义。xxx = scrapy.Field()

pipelines.py管道文件

爬虫主体文件

项目的设置文件

scrapy crawl gogogo

4.Scrapy结合Redis实现查重增量爬取

items.py依旧同上面的一致。需要哪些字段 自行定义。xxx = scrapy.Field()

pipelines.py管道文件

import pandas
import redis
import pymysql
import json
class SaveToMysqlPipeline(object):def __init__(self):self.redis_data_dict = '程序员客栈'self.redis_db = redis.Redis(host='127.0.0.1', port=6379, db=1)self.conn = pymysql.connect('localhost', port=3306, user='root', passwd='', db='forprogrammers')self.cur = self.conn.cursor()self.redis_db.flushdb()sql = """select user_city,user_nowcompany,user_nowoccupation,user_introduction,user_expectsalary,user_school,user_comment_number,source_link,user_ability_describe,user_name,user_picturehead,source_idfrom zc_user_detailswhere user_consultingsources = "程序员客栈""""  # 查询表中的现有数据df = pandas.read_sql(sql, self.conn)  # 读取mysql中的数据for index, row in df.iterrows():value = list(row.items())dic = dict(set(value))print(dic)self.redis_db.hset(self.redis_data_dict, dic['source_id'], json.dumps(dic))def process_item(self, item, spider):print(item)if self.redis_db.hexists(self.redis_data_dict, item['source_id']):  # 比较的是redis_data_dict里面的fieldif item == json.loads(self.redis_db.hget(self.redis_data_dict, item['source_id'])):print("数据库已经存在该条数据,且数据没有更新")else:self.do_update(item)else:self.do_insert(item)def do_insert(self, item):insert_sql = """insert into zc_user_details(user_city,user_nowcompany,user_nowoccupation,user_introduction,user_expectsalary,user_school,user_comment_number,source_link,user_ability_describe,user_name,user_picturehead,source_id,user_consultingsources)values(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""self.cur.execute(insert_sql, (item['user_city'],item['user_nowcompany'],item['user_nowoccupation'],item['user_introduction'],item['user_expectsalary'],item['user_school'],item['user_comment_number'],item['source_link'],item['user_ability_describe'],item['user_name'],item['user_picturehead'],item['source_id'],item['user_consultingsources']))self.conn.commit()print("*************************新增成功********************************************")return itemdef do_update(self, item):update_sql = """update zc_user_details set user_city=%s, user_nowcompany=%s, user_nowoccupation=%s, user_introduction=%s,user_expectsalary=%s, user_school=%s, user_comment_number=%s,user_ability_describe=%s,user_name=%s, user_picturehead=%s where source_id=%s"""self.cur.execute(update_sql, (item['user_city'],item['user_nowcompany'],item['user_nowoccupation'],item['user_introduction'],item['user_expectsalary'],item['user_school'],item['user_comment_number'],item['user_ability_describe'],item['user_name'],item['user_picturehead'],item['source_id']))self.conn.commit()print("*************************更新成功********************************************")def close_spider(self, spider):self.cur.close()self.conn.close()

爬虫主体文件项目的设置文件同上面保存到Mysql一致。

粗略记录 多多包涵。有需要的可以去我github上下载哈!

记 | 程序员客栈-爬虫记录(查重增量导出)相关推荐

  1. 【有三吐槽】程序员改BUG的六重境界,你,第几重了?

    文章首发于微信公众号<有三AI> [有三吐槽]程序员改BUG的六重境界,你,第几重了? 作为一个程序员,我们也有丰富多彩的bug人生啊,咱们又开新专栏了(实在是有感于最近大家问我的问题), ...

  2. 程序员客栈:程序员的经纪人_对于程序员:如何处理干扰和打扰

    程序员客栈:程序员的经纪人 您好亲爱的做白日梦的人,将咖啡因变成可待因! 我希望您不会因为一些破坏性通知或来自队友的推荐而来到这里,打扰您"检查他发现的这篇很棒的文章". 在接下来 ...

  3. 如何在YesDev,多团队协作程序员客栈的整包项目?

    程序员客栈平台项目协作 程序员客栈的整包项目,提供了一站式软件开发服务,智能匹配优质开发者,让客户拥有五星级的过程体验和交付质量.程序员客栈平台,目前已拥有61万+优秀开发者. 当程序员客栈的整包项目 ...

  4. 程序员客栈携手野狗 体验国内领先的实时后端云协作

    近日,国内领先的实时后端云"野狗wilddog"与国内领先的软件众包平台"程序员客栈"达成战略合作,计划通过程序员客栈众包平台发布的开发项目以及依托用户层面庞大 ...

  5. 给程序员的VIM速查卡

    摘自:http://coolshell.cn/articles/5479.html 这个速查卡来自这里.其用颜色标注了级别: Green   = 存活级 Yellow   = 感觉良好 Orange ...

  6. 推荐几个全网最全的程序员接私活地方法或完整攻略或常用平台以及接单的注意事项(以免被雇主坑),比如国内的程序员客栈、CODING 码市,国外的Upwork、Freelancer、Dribbble等。

    文章目录 1. 引言 2. 加QQ群.微信群等 3. 朋友.同事.同学介绍 4. 国内远程工作平台 4.1 程序员客栈 4.2 CODING 码市 4.3 开源众包 4.4 猪八戒 4.5 英选 4. ...

  7. 程序员客栈V4.24版本:设置主页访问密码

    一.写在前面 程序员客栈经过持续的版本迭代,在充分理解"技术人力"与"项目开发"业务的前提下,不断打磨优化签约接单.资质认证.技术信用.系统自动对接.招聘业务. ...

  8. 程序员客栈TOP收入的萌系开发者心得-雨晴

    雨晴,就和她的名字一样,有着萝莉的外表,温柔的性格.刚了解她时,甚至会担心是否能够承担这种偏男性的工种"产品经理".然而这个柔弱的妹子,在客栈不到一年的时间内,完成十多个不同项目, ...

  9. 微信小程序:多功能起名查重工具

    这是一个实用需求量还是比较高的一款微信小程序源码 由多个功能组合而成,具体如下 名字来源查询 取名工具(支持多种选择取名) 查询重复名(输入名字查询有多少人和你吃饭) 诗文(里面就是一些古诗啥的展示) ...

最新文章

  1. @responseBody和@RequestBody
  2. 一个跟jquery serializeArray()一起使用的函数,主要来方便提交表单。
  3. mongoose操作mongodb
  4. 如何部署 Hyperic ,使得从内网监测外网服务器
  5. linux查看服务端口号、查看端口(netstat、lsof)
  6. 大数据模型研究报告pdf_业绩大数据分析报告模型
  7. redis一般用来干嘛_谈谈redis的热key问题如何解决
  8. 5.1 API : SVC
  9. 第1章—Spring之旅—简化Spring的java开发
  10. 牛散村期货:3月春风生 第一周非农财经简阅
  11. 使用 Netsh.exe 配置 WinHTTP 的代理设置
  12. 作为非计算机专业的我,是如何拿下软考软件设计师的?
  13. WinXP下搭建适合Nokia开发的J2ME环境
  14. linux下声卡配置文件,Linux设备配置之声卡配置
  15. Linux桌面词典 GoldenDict词典
  16. C++-从cpp文件到exe文件的过程
  17. POJ 1088 滑雪 题解
  18. 炸!撩下 OLAP 数据分析的黑马神器 ClickHouse
  19. Android通知栏图标显示网络图片
  20. 如何将一个HTML页面嵌套在另一个页面中

热门文章

  1. 传奇外网架设常见的问题及解决办法-传奇创建人物失败/不开门/PAK显示密码错误/脚本错误
  2. 我的世界服务器指定等级指令,我的世界:服务器如何才能禁用高频红石?别用指令,必须要用它?...
  3. 什么蓝牙耳机适合学生党?平价好用蓝牙耳机推荐
  4. java实现微信、手机号登陆_微信小程序获取手机号授权用户登录功能
  5. Netty网络聊天(一) 聊天室实战
  6. 查找重复文件工具Easy Duplicate Finder
  7. python TypeError: ufunc 'subtract' did not contain a loop with signature matching types dtype('S32')
  8. CAD中插入外部参照字体会变繁体_为什么在CAD图纸中插入外部参照后会出现多余图形?...
  9. 科技驱动经济发展的时代全面到来
  10. oracle序列默认类型,ORACLE 序列-整理