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文件读写并使用mysql批量插入示例分享(python操作mysql)
Feb 17 Python
Python导入oracle数据的方法
Jul 10 Python
python中list列表的高级函数
May 17 Python
利用Python-iGraph如何绘制贴吧/微博的好友关系图详解
Nov 02 Python
Python读取系统文件夹内所有文件并统计数量的方法
Oct 23 Python
Python基于Logistic回归建模计算某银行在降低贷款拖欠率的数据示例
Jan 23 Python
Python + OpenCV 实现LBP特征提取的示例代码
Jul 11 Python
Python笔记之工厂模式
Nov 20 Python
Python enumerate函数遍历数据对象组合过程解析
Dec 11 Python
python实现企业微信定时发送文本消息的示例代码
Nov 24 Python
python爬虫scrapy基于CrawlSpider类的全站数据爬取示例解析
Feb 20 Python
教你使用pyinstaller打包Python教程
May 27 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 mssql 数据库分页SQL语句
2008/12/16 PHP
php 的加密函数 md5,crypt,base64_encode 等使用介绍
2012/04/09 PHP
PHP If Else(elsefi) 语句
2013/04/07 PHP
PHP解压tar.gz格式文件的方法
2016/02/14 PHP
php 判断过去离现在几年的函数(实例代码)
2016/11/15 PHP
php arsort 数组降序排序详细介绍
2016/11/17 PHP
PHP iconv()函数字符编码转换的问题讲解
2019/03/22 PHP
php的优点总结 php有哪些优点
2019/07/19 PHP
自动更新作用
2006/10/08 Javascript
Ajax,UTF-8还是GB2312 eval 还是execScript
2008/11/13 Javascript
解析js原生方法创建表格效率测试
2013/07/08 Javascript
取消选中单选框radio的三种方式示例介绍
2013/12/23 Javascript
JS解析XML文件和XML字符串详解
2015/04/17 Javascript
JavaScript使用RegExp进行正则匹配的方法
2015/07/11 Javascript
js实现三张图(文)片一起切换的banner焦点图
2015/08/25 Javascript
第九章之路径分页标签与徽章组件
2016/04/25 Javascript
JS for循环中i++ 和 ++i的区别介绍
2016/07/20 Javascript
javascript中this关键字详解
2016/12/12 Javascript
详解javascript获取url信息的常见方法
2016/12/19 Javascript
Vue2.0组件间数据传递示例
2017/03/07 Javascript
页面间固定参数,通过cookie传值的实现方法
2017/05/31 Javascript
webpack 2.x配置reactjs基本开发环境详解
2017/08/08 Javascript
Nodejs 复制文件/文件夹的方法
2017/08/24 NodeJs
Vue实现简易翻页效果源码分享
2018/11/08 Javascript
[30:51]DOTA2上海特级锦标赛主赛事日 - 3 胜者组第二轮#1Liquid VS MVP.Phx第一局
2016/03/04 DOTA
python处理图片之PIL模块简单使用方法
2015/05/11 Python
使用python爬取B站千万级数据
2018/06/08 Python
Python判断有效的数独算法示例
2019/02/23 Python
python读取dicom图像示例(SimpleITK和dicom包实现)
2020/01/16 Python
Python实现在线批量美颜功能过程解析
2020/06/10 Python
Keras 中Leaky ReLU等高级激活函数的用法
2020/07/05 Python
python3判断IP地址的方法
2021/03/04 Python
淮阳太昊陵导游词
2015/02/10 职场文书
学校2016年圣诞节活动总结
2016/03/31 职场文书
MySQL详解进行JDBC编程与增删改查方法
2022/06/16 MySQL