Python爬虫框架Scrapy实战之批量抓取招聘信息


Posted in Python onAugust 07, 2015

网络爬虫抓取特定网站网页的html数据,但是一个网站有上千上万条数据,我们不可能知道网站网页的url地址,所以,要有个技巧去抓取网站的所有html页面。Scrapy是纯Python实现的爬虫框架,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便~

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

Python爬虫框架Scrapy实战之批量抓取招聘信息

    绿线是数据流向,首先从初始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

Python爬虫框架Scrapy实战之批量抓取招聘信息

目标:抓取腾讯招聘官网职位招聘信息并保存为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里面定义我们要抓取的数据:

from scrapy.item import Item, Field 
class TencentItem(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:

import re 
import json 
from scrapy.selector import Selector 
try: 
  from scrapy.spider import Spider 
except: 
  from scrapy.spider import BaseSpider as Spider 
from scrapy.utils.response import get_base_url 
from scrapy.utils.url import urljoin_rfc 
from scrapy.contrib.spiders import CrawlSpider, Rule 
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor as sle 
from itzhaopin.items import * 
from itzhaopin.misc.log import * 
class TencentSpider(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') 
  ] 
  def parse_item(self, response): # 提取数据到Items里面,主要用到XPath和CSS选择器提取网页数据 
    items = [] 
    sel = Selector(response) 
    base_url = get_base_url(response) 
    sites_even = sel.css('table.tablelist tr.even') 
    for site in sites_even: 
      item = TencentItem() 
      item['name'] = site.css('.l.square a').xpath('text()').extract() 
      relative_url = site.css('.l.square a').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) 
      #print repr(item).decode("unicode-escape") + '\n' 
    sites_odd = sel.css('table.tablelist tr.odd') 
    for site in sites_odd: 
      item = TencentItem() 
      item['name'] = site.css('.l.square a').xpath('text()').extract() 
      relative_url = site.css('.l.square a').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) 
      #print repr(item).decode("unicode-escape") + '\n' 
    info('parsed ' + str(response)) 
    return items 
  def _process_request(self, request): 
    info('process ' + str(request)) 
    return request

实现PipeLine

PipeLine用来对Spider返回的Item列表进行保存操作,可以写入到文件、或者数据库等。

PipeLine只有一个需要实现的方法:process_item,例如我们将Item保存到JSON格式文件中:

pipelines.py

from scrapy import signals 
import json 
import codecs 
class JsonWithEncodingTencentPipeline(object): 
  def __init__(self): 
    self.file = codecs.open('tencent.json', 'w', encoding='utf-8') 
  def process_item(self, item, spider): 
    line = json.dumps(dict(item), ensure_ascii=False) + "\n" 
    self.file.write(line) 
    return item 
  def spider_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": ["深圳"]}

以上全部内容就是通过Python爬虫框架Scrapy实战之批量抓取招聘信息的全部内容,希望对大家有所帮助,欲了解更多编程知识,请锁定我们的网站,每天都有新的内容发布。

Python 相关文章推荐
python 控制语句
Nov 03 Python
python3.3使用tkinter开发猜数字游戏示例
Mar 14 Python
Python中使用第三方库xlrd来读取Excel示例
Apr 05 Python
python编程之requests在网络请求中添加cookies参数方法详解
Oct 25 Python
Python实现的多进程和多线程功能示例
May 29 Python
Django中使用Celery的方法示例
Nov 29 Python
使用Python开发SQLite代理服务器的方法
Dec 07 Python
Python3.5模块的定义、导入、优化操作图文详解
Apr 27 Python
python如何爬取网站数据并进行数据可视化
Jul 08 Python
在Python中使用filter去除列表中值为假及空字符串的例子
Nov 18 Python
Python拼接字符串的7种方式详解
Mar 19 Python
聊聊python在linux下与windows下导入模块的区别说明
Mar 03 Python
深入理解Python中命名空间的查找规则LEGB
Aug 06 #Python
举例详解Python中yield生成器的用法
Aug 05 #Python
Python中return语句用法实例分析
Aug 04 #Python
python函数形参用法实例分析
Aug 04 #Python
Python简明入门教程
Aug 04 #Python
将Python代码打包为jar软件的简单方法
Aug 04 #Python
python函数局部变量用法实例分析
Aug 04 #Python
You might like
做一个有下拉功能的留言版
2006/10/09 PHP
php调用mysql存储过程
2007/02/14 PHP
使用迭代器 遍历文件信息的详解
2013/06/08 PHP
php读取文件内容到数组的方法
2015/03/16 PHP
PHP+AjaxForm异步带进度条上传文件实例代码
2017/08/14 PHP
PHP自定义函数实现数组比较功能示例
2017/10/19 PHP
PHP以json或xml格式返回请求数据的方法
2018/05/31 PHP
ExtJS 简介 让你知道extjs是什么
2008/12/29 Javascript
jQuery 学习 几种常用方法
2009/06/11 Javascript
js获取事件源及触发该事件的对象
2013/10/24 Javascript
JS获取几种URL地址的方法小结
2014/02/26 Javascript
JavaScript操作Cookie详解
2015/02/28 Javascript
JavaScript数据结构与算法之栈与队列
2016/01/29 Javascript
浅析jquery数组删除指定元素的方法:grep()
2016/05/19 Javascript
JavaScript判断数组重复内容的两种方法(推荐)
2016/06/06 Javascript
JS中的==运算: [''] == false —>true
2016/07/24 Javascript
js友好的时间返回函数
2016/08/24 Javascript
vue获取dom元素注意事项
2017/12/28 Javascript
JS实现为动态创建的元素添加事件操作示例
2018/03/17 Javascript
小程序组件之自定义顶部导航实例
2019/06/12 Javascript
微信小程序之下拉列表实现方法解析(附完整源码)
2019/08/23 Javascript
如何修改Vue打包后文件的接口地址配置的方法
2020/04/22 Javascript
[01:29:42]Liquid vs VP Supermajor决赛 BO 第一场 6.10
2018/07/05 DOTA
Python通过属性手段实现只允许调用一次的示例讲解
2018/04/21 Python
flask入门之表单的实现
2018/07/18 Python
Django实现微信小程序的登录验证功能并维护登录态
2019/07/04 Python
用Python写一个自动木马程序
2019/09/17 Python
python内置函数sorted()用法深入分析
2019/10/08 Python
python 申请内存空间,用于创建多维数组的实例
2019/12/02 Python
python使用OpenCV模块实现图像的融合示例代码
2020/04/10 Python
Python类成员继承重写的实现
2020/09/16 Python
韩国家庭购物网上商店:Nsmall
2017/05/07 全球购物
全球500多个机场的接送服务:Suntransfers
2019/06/03 全球购物
在C语言中"指针和数组等价"到底是什么意思?
2014/03/24 面试题
期末自我鉴定
2014/02/02 职场文书
小喇叭开始广播了! 四十多年前珍贵老照片
2022/05/09 无线电