Python爬虫框架Scrapy实战之定向批量获取职位招聘信息

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

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

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

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

首先安装Scrapy

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

本文讲述了在64位 Ubuntu 12.04服务器上安装Scrapy的过程。

准备服务器

阿里云服务器配置

登录服务器

使用Putty登录服务器

安装Scrapy

导入GPG密钥

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 627220E7

添加软件源

echo 'deb http://archive.scrapy.org/ubuntu scrapy main' | sudo tee /etc/apt/sources.list.d/scrapy.list

更新包列表并安装scrapy

sudo apt-get update && sudo apt-get install scrapy-0.22

在本文中,我们将学会如何使用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] view plain copy

  1. from scrapy.item import Item, Field
  2. class TencentItem(Item):
  3. name = Field() # 职位名称
  4. catalog = Field() # 职位类别
  5. workLocation = Field() # 工作地点
  6. recruitNumber = Field() # 招聘人数
  7. detailLink = Field() # 职位详情页链接
  8. 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] view plain copy

  1. import re
  2. import json
  3. from scrapy.selector import Selector
  4. try:
  5. from scrapy.spider import Spider
  6. except:
  7. from scrapy.spider import BaseSpider as Spider
  8. from scrapy.utils.response import get_base_url
  9. from scrapy.utils.url import urljoin_rfc
  10. from scrapy.contrib.spiders import CrawlSpider, Rule
  11. from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor as sle
  12. from itzhaopin.items import *
  13. from itzhaopin.misc.log import *
  14. class TencentSpider(CrawlSpider):
  15. name = "tencent"
  16. allowed_domains = ["tencent.com"]
  17. start_urls = [
  18. "http://hr.tencent.com/position.php"
  19. ]
  20. rules = [ # 定义爬取URL的规则
  21. Rule(sle(allow=("/position.php\?&start=\d{,4}#a")), follow=True, callback='parse_item')
  22. ]
  23. def parse_item(self, response): # 提取数据到Items里面,主要用到XPath和CSS选择器提取网页数据
  24. items = []
  25. sel = Selector(response)
  26. base_url = get_base_url(response)
  27. sites_even = sel.css('table.tablelist tr.even')
  28. for site in sites_even:
  29. item = TencentItem()
  30. item['name'] = site.css('.l.square a').xpath('text()').extract()
  31. relative_url = site.css('.l.square a').xpath('@href').extract()[0]
  32. item['detailLink'] = urljoin_rfc(base_url, relative_url)
  33. item['catalog'] = site.css('tr > td:nth-child(2)::text').extract()
  34. item['workLocation'] = site.css('tr > td:nth-child(4)::text').extract()
  35. item['recruitNumber'] = site.css('tr > td:nth-child(3)::text').extract()
  36. item['publishTime'] = site.css('tr > td:nth-child(5)::text').extract()
  37. items.append(item)
  38. #print repr(item).decode("unicode-escape") + '\n'
  39. sites_odd = sel.css('table.tablelist tr.odd')
  40. for site in sites_odd:
  41. item = TencentItem()
  42. item['name'] = site.css('.l.square a').xpath('text()').extract()
  43. relative_url = site.css('.l.square a').xpath('@href').extract()[0]
  44. item['detailLink'] = urljoin_rfc(base_url, relative_url)
  45. item['catalog'] = site.css('tr > td:nth-child(2)::text').extract()
  46. item['workLocation'] = site.css('tr > td:nth-child(4)::text').extract()
  47. item['recruitNumber'] = site.css('tr > td:nth-child(3)::text').extract()
  48. item['publishTime'] = site.css('tr > td:nth-child(5)::text').extract()
  49. items.append(item)
  50. #print repr(item).decode("unicode-escape") + '\n'
  51. info('parsed ' + str(response))
  52. return items
  53. def _process_request(self, request):
  54. info('process ' + str(request))
  55. return request

实现PipeLine

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

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

pipelines.py

[python] view plain copy

  1. from scrapy import signals
  2. import json
  3. import codecs
  4. class JsonWithEncodingTencentPipeline(object):
  5. def __init__(self):
  6. self.file = codecs.open('tencent.json', 'w', encoding='utf-8')
  7. def process_item(self, item, spider):
  8. line = json.dumps(dict(item), ensure_ascii=False) + "\n"
  9. self.file.write(line)
  10. return item
  11. def spider_closed(self, spider):
  12. self.file.close(
  13. )

到现在,我们就完成了一个基本的爬虫的实现,可以输入下面的命令来启动这个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将JSON格式数据转换为SQL语句以便导入MySQL数据库

前文中我们把网络爬虫爬取的数据保存为JSON格式,但为了能够更方便地处理数据,我们希望把这些数据导入到MySQL数据库中。phpMyadmin可以把MySQL数据库中的数据导出为JSON格式文件,但却不能把JSON格式文件导入到MySQL数据库。为了实现这个目标,可以编写Python脚本将JSON格式数据转换为SQL语句以便导入MySQL数据库。

JSON文件tencent.json部分内容:

{"recruitNumber": "1", "name": "SD10-FPS俄语游戏海外PM(深圳)", "detailLink": "http://hr.tencent.com/position_detail.php?id=9587&keywords=&tid=0&lid=0", "publishTime": "2013-11-13", "catalog": "产品/项目类", "workLocation": "深圳"} {"recruitNumber": "2", "name": "HY2-互动娱乐游戏网游财产安全运营专员(深圳)", "detailLink": "http://hr.tencent.com/position_detail.php?id=9482&keywords=&tid=0&lid=0", "publishTime": "2013-11-28", "catalog": "产品/项目类", "workLocation": "深圳"}

在phpMyadmin中创建数据库及表结构:

[sql] view plain copy

  1. CREATE DATABASE itzhaopin;

[sql] view plain copy

  1. CREATE TABLE IF NOT EXISTS `tencent` (
  2. `id` int(11) NOT NULL auto_increment,
  3. `name` varchar(512) default NULL,
  4. `catalog` varchar(64) default NULL,
  5. `workLocation` varchar(64) default NULL,
  6. `recruitNumber` varchar(64) default NULL,
  7. `detailLink` varchar(1024) default NULL,
  8. `publishTime` varchar(64) default NULL,
  9. PRIMARY KEY (`ID`)
  10. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

编写Python脚本json2sql.py将JSON格式数据转换为SQL语句:

[python] view plain cop

  1. #-*- coding: UTF-8 -*-
  2. import json
  3. data = []
  4. with open('itzhaopin/tencent.json') as f:
  5. for line in f:
  6. data.append(json.loads(line))
  7. #print json.dumps(data, ensure_ascii=False)
  8. str = "\r\n"
  9. for item in data:
  10. #print json.dumps(item)
  11. str = str + "insert into tencent(name,catalog,workLocation,recruitNumber,detailLink,publishTime) values "
  12. str = str + "('%s','%s','%s','%s','%s','%s');\r\n" % (item['name'],item['catalog'],item['workLocation'],item['recruitNumber'],item['detailLink'],item['publishTime'])
  13. import codecs
  14. file_object = codecs.open('tencent.sql', 'w' ,"utf-8")
  15. file_object.write(str)
  16. file_object.close()
  17. print "success"

执行该python脚本,在当前目录下将生成一个名为tencent.sql的文件,在phpMyadmin中导入并执行该文件,爬虫抓取的数据将导入MySQL数据库。(via:http://blog.csdn.net/HanTangSongMing/article/details/24454453)

原文发布于微信公众号 - 大数据挖掘DT数据分析(datadw)

原文发表时间:2016-05-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小白客

学习编程的你,遇到了Bug该怎么办?

这里我先回答标题的问题,答案就是:百度! 直接把错误提示复制在搜索栏,用百度搜索。如果没有现成的错误提示,只有模糊的需求,那就整理一下需求,组织一下语言,然后...

3414
来自专栏华章科技

资源整理 | 32个Python爬虫项目让你一次吃到撑

整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心。所有链接指向GitHub,祝大家玩的愉快~

1502
来自专栏Python中文社区

Python网络爬虫实战项目大全,最后一个亮了

wcspider [1]- 微信公众号爬虫。使用爬虫搜索所有微信公众号资料及其文章,通过搜狗搜索获取公众号的openid,创建公众号历史消息请求URL,解析出历...

2546
来自专栏华章科技

520特别版Python实战:教你用微信每天给TA说晚安

from __future__ import unicode_literals from threading import Timer from wxpy i...

1021
来自专栏BestSDK

最全Python爬虫:微信、知乎、豆瓣,一次“偷”个够!

WechatSogou [1]– 微信公众号爬虫。基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字...

9646
来自专栏有趣的Python

2018.8.21重磅更新!!!: FunpySpiderSearch-ElasticSearch or Mysql 搜索引擎全面更新!!!

2018.08.21 最新可用Scrapy1.5.1爬取数据 + ElasticSearch6.3.2 存储数据并提供对外Restful Api + Djang...

1193
来自专栏Python中文社区

微博爬虫开源项目汇总大全

- [SinaSpider][1] - 基于scrapy和redis的分布式微博爬虫。SinaSpider主要爬取新浪微博的个人信息、微博数据、关注和粉丝。数...

2808
来自专栏牛客网

VIPKID Java工程师一面

622
来自专栏程序员宝库

如何做一个小程序口令红包功能

作者:张先生 原文:https://segmentfault.com/a/1190000011014127 在做小程序后端支持的过程中遇到不少有意思的功能,有...

38110
来自专栏北京马哥教育

一天可抓取 1300 万条数据的新浪微博爬虫

爬虫功能: 此项目和QQ空间爬虫类似,主要爬取新浪微博用户的个人信息、微博信息、粉丝和关注(详细见此:https://github.com/LiuXingMin...

3818

扫码关注云+社区