设为首页 收藏本站
查看: 808|回复: 0

[经验分享] Python爬虫框架Scrapy实战之定向批量获取职位招聘信息

[复制链接]

尚未签到

发表于 2017-5-8 09:57:09 | 显示全部楼层 |阅读模式
所谓网络爬虫,就是一个在网上到处或定向抓取数据的程序,当然,这种说法不够专业,更专业的描述就是,抓取特定网站网页的HTML数据。不过由于一个网站的网页很多,而我们又不可能事先知道所有网页的URL地址,所以,如何保证我们抓取到了网站的所有HTML页面就是一个有待考究的问题了。一般的方法是,定义一个入口页面,然后一般一个页面会有其他页面的URL,于是从当前页面获取到这些URL加入到爬虫的抓取队列中,然后进入到新页面后再递归的进行上述的操作,其实说来就跟深度遍历或广度遍历一样。

Scrapy是一个基于Twisted,纯Python实现的爬虫框架,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便~

Scrapy 使用 Twisted这个异步网络库来处理网络通讯,架构清晰,并且包含了各种中间件接口,可以灵活的完成各种需求。整体架构如下图所示:
DSC0000.jpg

绿线是数据流向,首先从初始URL 开始,Scheduler 会将其交给 Downloader 进行下载,下载之后会交给 Spider 进行分析,Spider分析出来的结果有两种:一种是需要进一步抓取的链接,例如之前分析的“下一页”的链接,这些东西会被传回 Scheduler ;另一种是需要保存的数据,它们则被送到Item Pipeline 那里,那是对数据进行后期处理(详细分析、过滤、存储等)的地方。另外,在数据流动的通道里还可以安装各种中间件,进行必要的处理。




我假定你已经安装了Scrapy。假如你没有安装,你可以参考这篇文章。

在本文中,我们将学会如何使用Scrapy建立一个爬虫程序,并爬取指定网站上的内容
1. 创建一个新的Scrapy Project
2. 定义你需要从网页中提取的元素Item
3.实现一个Spider类,通过接口完成爬取URL和提取Item的功能
4. 实现一个Item PipeLine类,完成Item的存储功能

我将会用腾讯招聘官网作为例子。
Github源码:https://github.com/maxliaops/scrapy-itzhaopin
DSC0001.jpg

目标:抓取腾讯招聘官网职位招聘信息并保存为JSON格式。


新建工程
首先,为我们的爬虫新建一个工程,首先进入一个目录(任意一个我们用来保存代码的目录),执行:
scrapy startprojectitzhaopin

最后的itzhaopin就是项目名称。这个命令会在当前目录下创建一个新目录itzhaopin,结构如下:
.
├── itzhaopin
│ ├── itzhaopin
│ │ ├── __init__.py
│ │ ├── items.py
│ │ ├── pipelines.py
│ │ ├── settings.py
│ │ └── spiders
│ │└── __init__.py
│ └── scrapy.cfg

scrapy.cfg: 项目配置文件
items.py: 需要提取的数据结构定义文件
pipelines.py:管道定义,用来对items里面提取的数据做进一步处理,如保存等
settings.py: 爬虫配置文件
spiders: 放置spider的目录


定义Item
在items.py里面定义我们要抓取的数据:

[python]viewplaincopy



  • fromscrapy.itemimportItem,Field
  • classTencentItem(Item):
  • name=Field()#职位名称
  • catalog=Field()#职位类别
  • workLocation=Field()#工作地点
  • recruitNumber=Field()#招聘人数
  • detailLink=Field()#职位详情页链接
  • publishTime=Field()#发布时间


实现Spider
Spider是一个继承自scrapy.contrib.spiders.CrawlSpider的Python类,有三个必需的定义的成员
name: 名字,这个spider的标识
start_urls:一个url列表,spider从这些网页开始抓取
parse():一个方法,当start_urls里面的网页抓取下来之后需要调用这个方法解析网页内容,同时需要返回下一个需要抓取的网页,或者返回items列表
所以在spiders目录下新建一个spider,tencent_spider.py:
[python]viewplaincopy



  • importre
  • importjson


  • fromscrapy.selectorimportSelector
  • try:
  • fromscrapy.spiderimportSpider
  • except:
  • fromscrapy.spiderimportBaseSpiderasSpider
  • fromscrapy.utils.responseimportget_base_url
  • fromscrapy.utils.urlimporturljoin_rfc
  • fromscrapy.contrib.spidersimportCrawlSpider,Rule
  • fromscrapy.contrib.linkextractors.sgmlimportSgmlLinkExtractorassle


  • fromitzhaopin.itemsimport*
  • fromitzhaopin.misc.logimport*


  • classTencentSpider(CrawlSpider):
  • name="tencent"
  • allowed_domains=["tencent.com"]
  • start_urls=[
  • "http://hr.tencent.com/position.php"
  • ]
  • rules=[#定义爬取URL的规则
  • Rule(sle(allow=("/position.php\?&start=\d{,4}#a")),follow=True,callback='parse_item')
  • ]

  • defparse_item(self,response):#提取数据到Items里面,主要用到XPath和CSS选择器提取网页数据
  • items=[]
  • sel=Selector(response)
  • base_url=get_base_url(response)
  • sites_even=sel.css('table.tablelisttr.even')
  • forsiteinsites_even:
  • item=TencentItem()
  • item['name']=site.css('.l.squarea').xpath('text()').extract()
  • relative_url=site.css('.l.squarea').xpath('@href').extract()[0]
  • item['detailLink']=urljoin_rfc(base_url,relative_url)
  • item['catalog']=site.css('tr>td:nth-child(2)::text').extract()
  • item['workLocation']=site.css('tr>td:nth-child(4)::text').extract()
  • item['recruitNumber']=site.css('tr>td:nth-child(3)::text').extract()
  • item['publishTime']=site.css('tr>td:nth-child(5)::text').extract()
  • items.append(item)
  • #printrepr(item).decode("unicode-escape")+'\n'

  • sites_odd=sel.css('table.tablelisttr.odd')
  • forsiteinsites_odd:
  • item=TencentItem()
  • item['name']=site.css('.l.squarea').xpath('text()').extract()
  • relative_url=site.css('.l.squarea').xpath('@href').extract()[0]
  • item['detailLink']=urljoin_rfc(base_url,relative_url)
  • item['catalog']=site.css('tr>td:nth-child(2)::text').extract()
  • item['workLocation']=site.css('tr>td:nth-child(4)::text').extract()
  • item['recruitNumber']=site.css('tr>td:nth-child(3)::text').extract()
  • item['publishTime']=site.css('tr>td:nth-child(5)::text').extract()
  • items.append(item)
  • #printrepr(item).decode("unicode-escape")+'\n'

  • info('parsed'+str(response))
  • returnitems


  • def_process_request(self,request):
  • info('process'+str(request))
  • returnrequest


实现PipeLine

PipeLine用来对Spider返回的Item列表进行保存操作,可以写入到文件、或者数据库等。
PipeLine只有一个需要实现的方法:process_item,例如我们将Item保存到JSON格式文件中:

pipelines.py
[python]viewplaincopy



  • fromscrapyimportsignals
  • importjson
  • importcodecs

  • classJsonWithEncodingTencentPipeline(object):

  • def__init__(self):
  • self.file=codecs.open('tencent.json','w',encoding='utf-8')

  • defprocess_item(self,item,spider):
  • line=json.dumps(dict(item),ensure_ascii=False)+"\n"
  • self.file.write(line)
  • returnitem

  • defspider_closed(self,spider):
  • self.file.close(
  • )


到现在,我们就完成了一个基本的爬虫的实现,可以输入下面的命令来启动这个Spider:
scrapy crawl tencent

爬虫运行结束后,在当前目录下将会生成一个名为tencent.json的文件,其中以JSON格式保存了职位招聘信息。
部分内容如下:
{"recruitNumber": ["1"], "name": ["SD5-资深手游策划(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15626&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["产品/项目类"], "workLocation": ["深圳"]}
{"recruitNumber": ["1"], "name": ["TEG13-后台开发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15666&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["2"], "name": ["TEG12-数据中心高级经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15698&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["1"], "name": ["GY1-微信支付品牌策划经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15710&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["市场类"], "workLocation": ["深圳"]}
{"recruitNumber": ["2"], "name": ["SNG06-后台开发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15499&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["2"], "name": ["OMG01-腾讯时尚视频策划编辑(北京)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15694&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["内容编辑类"], "workLocation": ["北京"]}
{"recruitNumber": ["1"], "name": ["HY08-QT客户端Windows开发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=11378&keywords=&tid=0&lid=0", "publishTime":["2014-04-25"], "catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["5"], "name": ["HY1-移动游戏测试经理(上海)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15607&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["上海"]}
{"recruitNumber": ["1"], "name": ["HY6-网吧平台高级产品经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=10974&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["产品/项目类"], "workLocation": ["深圳"]}
{"recruitNumber": ["4"], "name": ["TEG14-云存储研发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15168&keywords=&tid=0&lid=0", "publishTime": ["2014-04-24"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["1"], "name": ["CB-薪酬经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=2309&keywords=&tid=0&lid=0", "publishTime": ["2013-11-28"],"catalog": ["职能类"], "workLocation": ["深圳"]}


所谓网络爬虫,就是一个在网上到处或定向抓取数据的程序,当然,这种说法不够专业,更专业的描述就是,抓取特定网站网页的HTML数据。不过由于一个网站的网页很多,而我们又不可能事先知道所有网页的URL地址,所以,如何保证我们抓取到了网站的所有HTML页面就是一个有待考究的问题了。一般的方法是,定义一个入口页面,然后一般一个页面会有其他页面的URL,于是从当前页面获取到这些URL加入到爬虫的抓取队列中,然后进入到新页面后再递归的进行上述的操作,其实说来就跟深度遍历或广度遍历一样。

Scrapy是一个基于Twisted,纯Python实现的爬虫框架,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便~

Scrapy 使用 Twisted这个异步网络库来处理网络通讯,架构清晰,并且包含了各种中间件接口,可以灵活的完成各种需求。整体架构如下图所示:


绿线是数据流向,首先从初始URL 开始,Scheduler 会将其交给 Downloader 进行下载,下载之后会交给 Spider 进行分析,Spider分析出来的结果有两种:一种是需要进一步抓取的链接,例如之前分析的“下一页”的链接,这些东西会被传回 Scheduler ;另一种是需要保存的数据,它们则被送到Item Pipeline 那里,那是对数据进行后期处理(详细分析、过滤、存储等)的地方。另外,在数据流动的通道里还可以安装各种中间件,进行必要的处理。




我假定你已经安装了Scrapy。假如你没有安装,你可以参考这篇文章。

在本文中,我们将学会如何使用Scrapy建立一个爬虫程序,并爬取指定网站上的内容
1. 创建一个新的Scrapy Project
2. 定义你需要从网页中提取的元素Item
3.实现一个Spider类,通过接口完成爬取URL和提取Item的功能
4. 实现一个Item PipeLine类,完成Item的存储功能

我将会用腾讯招聘官网作为例子。
Github源码:https://github.com/maxliaops/scrapy-itzhaopin


目标:抓取腾讯招聘官网职位招聘信息并保存为JSON格式。


新建工程
首先,为我们的爬虫新建一个工程,首先进入一个目录(任意一个我们用来保存代码的目录),执行:
scrapy startprojectitzhaopin

最后的itzhaopin就是项目名称。这个命令会在当前目录下创建一个新目录itzhaopin,结构如下:
.
├── itzhaopin
│ ├── itzhaopin
│ │ ├── __init__.py
│ │ ├── items.py
│ │ ├── pipelines.py
│ │ ├── settings.py
│ │ └── spiders
│ │└── __init__.py
│ └── scrapy.cfg

scrapy.cfg: 项目配置文件
items.py: 需要提取的数据结构定义文件
pipelines.py:管道定义,用来对items里面提取的数据做进一步处理,如保存等
settings.py: 爬虫配置文件
spiders: 放置spider的目录


定义Item
在items.py里面定义我们要抓取的数据:

[python]viewplaincopy



  • fromscrapy.itemimportItem,Field
  • classTencentItem(Item):
  • name=Field()#职位名称
  • catalog=Field()#职位类别
  • workLocation=Field()#工作地点
  • recruitNumber=Field()#招聘人数
  • detailLink=Field()#职位详情页链接
  • publishTime=Field()#发布时间


实现Spider
Spider是一个继承自scrapy.contrib.spiders.CrawlSpider的Python类,有三个必需的定义的成员
name: 名字,这个spider的标识
start_urls:一个url列表,spider从这些网页开始抓取
parse():一个方法,当start_urls里面的网页抓取下来之后需要调用这个方法解析网页内容,同时需要返回下一个需要抓取的网页,或者返回items列表
所以在spiders目录下新建一个spider,tencent_spider.py:
[python]viewplaincopy



  • importre
  • importjson


  • fromscrapy.selectorimportSelector
  • try:
  • fromscrapy.spiderimportSpider
  • except:
  • fromscrapy.spiderimportBaseSpiderasSpider
  • fromscrapy.utils.responseimportget_base_url
  • fromscrapy.utils.urlimporturljoin_rfc
  • fromscrapy.contrib.spidersimportCrawlSpider,Rule
  • fromscrapy.contrib.linkextractors.sgmlimportSgmlLinkExtractorassle


  • fromitzhaopin.itemsimport*
  • fromitzhaopin.misc.logimport*


  • classTencentSpider(CrawlSpider):
  • name="tencent"
  • allowed_domains=["tencent.com"]
  • start_urls=[
  • "http://hr.tencent.com/position.php"
  • ]
  • rules=[#定义爬取URL的规则
  • Rule(sle(allow=("/position.php\?&start=\d{,4}#a")),follow=True,callback='parse_item')
  • ]

  • defparse_item(self,response):#提取数据到Items里面,主要用到XPath和CSS选择器提取网页数据
  • items=[]
  • sel=Selector(response)
  • base_url=get_base_url(response)
  • sites_even=sel.css('table.tablelisttr.even')
  • forsiteinsites_even:
  • item=TencentItem()
  • item['name']=site.css('.l.squarea').xpath('text()').extract()
  • relative_url=site.css('.l.squarea').xpath('@href').extract()[0]
  • item['detailLink']=urljoin_rfc(base_url,relative_url)
  • item['catalog']=site.css('tr>td:nth-child(2)::text').extract()
  • item['workLocation']=site.css('tr>td:nth-child(4)::text').extract()
  • item['recruitNumber']=site.css('tr>td:nth-child(3)::text').extract()
  • item['publishTime']=site.css('tr>td:nth-child(5)::text').extract()
  • items.append(item)
  • #printrepr(item).decode("unicode-escape")+'\n'

  • sites_odd=sel.css('table.tablelisttr.odd')
  • forsiteinsites_odd:
  • item=TencentItem()
  • item['name']=site.css('.l.squarea').xpath('text()').extract()
  • relative_url=site.css('.l.squarea').xpath('@href').extract()[0]
  • item['detailLink']=urljoin_rfc(base_url,relative_url)
  • item['catalog']=site.css('tr>td:nth-child(2)::text').extract()
  • item['workLocation']=site.css('tr>td:nth-child(4)::text').extract()
  • item['recruitNumber']=site.css('tr>td:nth-child(3)::text').extract()
  • item['publishTime']=site.css('tr>td:nth-child(5)::text').extract()
  • items.append(item)
  • #printrepr(item).decode("unicode-escape")+'\n'

  • info('parsed'+str(response))
  • returnitems


  • def_process_request(self,request):
  • info('process'+str(request))
  • returnrequest


实现PipeLine

PipeLine用来对Spider返回的Item列表进行保存操作,可以写入到文件、或者数据库等。
PipeLine只有一个需要实现的方法:process_item,例如我们将Item保存到JSON格式文件中:

pipelines.py
[python]viewplaincopy



  • fromscrapyimportsignals
  • importjson
  • importcodecs

  • classJsonWithEncodingTencentPipeline(object):

  • def__init__(self):
  • self.file=codecs.open('tencent.json','w',encoding='utf-8')

  • defprocess_item(self,item,spider):
  • line=json.dumps(dict(item),ensure_ascii=False)+"\n"
  • self.file.write(line)
  • returnitem

  • defspider_closed(self,spider):
  • self.file.close(
  • )


到现在,我们就完成了一个基本的爬虫的实现,可以输入下面的命令来启动这个Spider:
scrapy crawl tencent

爬虫运行结束后,在当前目录下将会生成一个名为tencent.json的文件,其中以JSON格式保存了职位招聘信息。
部分内容如下:
{"recruitNumber": ["1"], "name": ["SD5-资深手游策划(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15626&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["产品/项目类"], "workLocation": ["深圳"]}
{"recruitNumber": ["1"], "name": ["TEG13-后台开发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15666&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["2"], "name": ["TEG12-数据中心高级经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15698&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["1"], "name": ["GY1-微信支付品牌策划经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15710&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["市场类"], "workLocation": ["深圳"]}
{"recruitNumber": ["2"], "name": ["SNG06-后台开发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15499&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["2"], "name": ["OMG01-腾讯时尚视频策划编辑(北京)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15694&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["内容编辑类"], "workLocation": ["北京"]}
{"recruitNumber": ["1"], "name": ["HY08-QT客户端Windows开发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=11378&keywords=&tid=0&lid=0", "publishTime":["2014-04-25"], "catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["5"], "name": ["HY1-移动游戏测试经理(上海)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15607&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["技术类"], "workLocation": ["上海"]}
{"recruitNumber": ["1"], "name": ["HY6-网吧平台高级产品经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=10974&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"],"catalog": ["产品/项目类"], "workLocation": ["深圳"]}
{"recruitNumber": ["4"], "name": ["TEG14-云存储研发工程师(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15168&keywords=&tid=0&lid=0", "publishTime": ["2014-04-24"],"catalog": ["技术类"], "workLocation": ["深圳"]}
{"recruitNumber": ["1"], "name": ["CB-薪酬经理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=2309&keywords=&tid=0&lid=0", "publishTime": ["2013-11-28"],"catalog": ["职能类"], "workLocation": ["深圳"]}


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-374515-1-1.html 上篇帖子: 机器学习算法与Python实践之(三)支持向量机(SVM)进阶 下篇帖子: Learn Python The Hard Way学习(51)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表