python爬虫实战(1) -- 抓取boss直聘招聘信息

系列文章
python爬虫实战(1) -- 抓取boss直聘招聘信息
python爬虫实战(2) -- MongoDB和数据清洗
python爬虫实战(3) -- 数据可视化

实验内容:爬取boss直聘的岗位信息,存储在数据库,最后通过可视化展示出来

参考:jtahstu https://segmentfault.com/a/1190000012390223

0 环境搭建

  • MacBook Air (13-inch, 2017)
  • CPU:1.8 GHz Intel Core i5
  • RAM:8 GB 1600 MHz DDR3
  • IDE:anaconda3.6 | jupyter notebook
  • Python版本:Python 3.6.5 :: Anaconda, Inc.

1 安装scrapy

过程在参考链接中,我只说与上面不一致的地方

pip install scrapy
  • 遇到报错,无法调用gcc
    *解决方案:mac自动弹出安装gcc提示框,点击“安装”即可
  • 安装成功,安装过程中,终端打印出“distributed 1.21.8 requires msgpack, which is not installed.”
    • 解决方案:
conda install -c anaconda msgpack-python
pip install msgpack

参考:https://stackoverflow.com/questions/51050257/distributed-1-21-8-requires-msgpack-which-is-not-installed

2 新建项目

scrapy startproject www_zhipin_com
可以通过 scrapy -h 了解功能
源码文件关系

tree这个命令挺好用,微软cmd中自带,Python没有自带的,可以参考网上代码,自己写一个玩玩。

3 定义要抓取的item

与源代码基本一致

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class WwwZhipinComItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pid = scrapy.Field()
    positionName = scrapy.Field()
    positionLables = scrapy.Field()
    city = scrapy.Field()
    experience = scrapy.Field()
    educational = scrapy.Field()
    salary = scrapy.Field()
    company = scrapy.Field()
    industryField = scrapy.Field()
    financeStage = scrapy.Field()
    companySize = scrapy.Field()
    time = scrapy.Field()
    updated_at = scrapy.Field()

4 分析页面

现在页面改版了,发布时间有了小幅度调整


页面
HTML结构如下

5 爬虫代码

这一步有些看不懂,硬着头皮往下写,不懂得先记着

5.1关于request headers

比如headers中,我在自己的浏览器中找不到下面内容
x-devtools-emulate-network-conditions-client-id ??
postman-token ??

参考有x-devtools的网页
https://bbs.csdn.net/topics/390893160
http://www.cnblogs.com/iloverain/p/9198217.html

我该学习一下request headers中内容
目前采用的方法是把作者的headers拷贝过去,然后我这边有的我替换掉,没有的比如x-devtools我就用作者原有的。

5.2 关于extract_first()和extract()

scrapy实战还是蛮多的
看到有个爬取豆瓣内容的 https://www.jianshu.com/p/f36460267ac2

extract_first()和extract()的区别:
提取全部内容: .extract(),获得是一个列表
提取第一个:.extract_first(),获得是一个字符串

Selectors根据CSS表达式从网页中选择数据(CSS更常用)
response.selector.css('title::text') ##用css选取了title的文字内容
由于selector.css使用比较普遍,所以专门定义了css,所以上面也可以写成:
response.css('title::text')

看到有个运维学python的,使用py3.6,写的很实战,mark
运维学python之爬虫高级篇(五)scrapy爬取豆瓣电影TOP250
运维学python之爬虫高级篇(四)Item Pipeline介绍(附爬取网站获取图片到本地代码)
运维学python之爬虫高级篇(三)spider和items介绍
运维学python之爬虫高级篇(二)用Scrapy框架实现简单爬虫
运维学python之爬虫高级篇(一)Scrapy框架入门
运维学python之爬虫中级篇(九)Python3 MySQL 数据库连接
运维学python之爬虫中级篇(八)MongoDB
运维学python之爬虫中级篇(七)Sqlite3
运维学python之爬虫中级篇(六)基础爬虫
运维学python之爬虫中级篇(五)数据存储(无数据库版)
运维学python之爬虫中级篇(四)网络编程
运维学python之爬虫中级篇(三)分布式进程
运维学python之爬虫中级篇(二)线程、协程
运维学python之爬虫中级篇(一)进程
运维学python之爬虫工具篇(六)Pyquery的用法
运维学python之爬虫工具篇(五)Selenium的用法
运维学python之爬虫工具篇(四)PhantomJS的用法
运维学python之爬虫工具篇(三)Xpath语法与lxml库的用法
运维学python之爬虫工具篇(二)Beautiful Soup的用法
运维学python之爬虫工具篇(一)Requests库的用法
运维学python之爬虫基础篇实战(七)爬取伯乐在线面向对象图片
运维学python之爬虫基础篇实战(六)爬取百度贴吧
运维学python之爬虫基础篇(五)正则表达式
运维学python之爬虫基础篇(四)Cookie
运维学python之爬虫基础篇(三)urllib模块高级用法
运维学python之爬虫基础篇(二)urllib模块使用
运维学python之爬虫基础篇(一)开篇

运行脚本,会在项目目录下生成一个包含爬取数据的item.json文件
scrapy crawl zhipin -o item.json

debug完最后一个错误之后,第五步终于跑通了,截个图


爬取boss直聘上面关于python的职位

存入json文件的模样有点奇怪,没汉字,第六步应该会解决:

{"pid": "23056497", "positionName": "", "salary": "8k-9k", "city": "\u5317\u4eac", "experience": "\u4e0d\u9650", "educational": "\u672c\u79d1", "company": "\u4eca\u65e5\u5934\u6761", "positionLables": [], "time": "\u53d1\u5e03\u4e8e07\u670812\u65e5", "updated_at": "2018-07-17 00:04:05"},
{"pid": "23066797", "positionName": "", "salary": "18k-25k", "city": "\u5317\u4eac", "experience": "1-3\u5e74", "educational": "\u672c\u79d1", "company": "\u5929\u4e0b\u79c0", "positionLables": [], "time": "\u53d1\u5e03\u4e8e07\u670813\u65e5", "updated_at": "2018-07-17 00:04:05"},

第五步因为网页发生改版,所以发布时间time这块需要修改一下,其他都没有问题。
我也把源码贴一下:

# 2018-07-17 
# Author limingxuan 
# limx2011@hotmail.com
# blog:https://www.jianshu.com/p/a5907362ba72

import scrapy
import time
from www_zhipin_com.items import WwwZhipinComItem

class ZhipinSpider(scrapy.Spider):
    name = 'zhipin'
    allowed_domains = ['www.zhipin.com']
    start_urls = ['http://www.zhipin.com/']
    positionUrl = 'https://www.zhipin.com/job_detail/?query=python&scity=101010100'
    curPage = 1
    #我的浏览器找不到源码中的一些字段,比如
    #x-devtools-emulate-network-conditions-client-id
    #upgrade-insecure-requests
    #dnt
    #cache-control
    #postman-token
    #所以就没有加,按我的浏览器查到的信息填写的,现在看起来貌似也能跑起来
    headers = {    
    'accept': "application/json, text/javascript, */*; q=0.01",
    'accept-encoding': "gzip, deflate, br",
    'accept-language': "zh-CN,zh;q=0.9,en;q=0.8",
    'content-type': "application/x-www-form-urlencoded; charset=UTF-8",
    'cookie': "JSESSIONID=""; __c=1530137184; sid=sem_pz_bdpc_dasou_title; __g=sem_pz_bdpc_dasou_title; __l=r=https%3A%2F%2Fwww.zhipin.com%2Fgongsi%2F5189f3fadb73e42f1HN40t8~.html&l=%2Fwww.zhipin.com%2Fgongsir%2F5189f3fadb73e42f1HN40t8~.html%3Fka%3Dcompany-jobs&g=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1531150234,1531231870,1531573701,1531741316; lastCity=101010100; toUrl=https%3A%2F%2Fwww.zhipin.com%2Fjob_detail%2F%3Fquery%3Dpython%26scity%3D101010100; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1531743361; __a=26651524.1530136298.1530136298.1530137184.286.2.285.199",
    'origin': "https://www.zhipin.com",
    'referer': "https://www.zhipin.com/job_detail/?query=python&scity=101010100",
    'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
    }
    
    def start_requests(self):
        return [self.next_request()]
    
    def parse(self,response):
        print("request -> " + response.url)
        job_list = response.css('div.job-list > ul > li')
        for job in job_list:
            item = WwwZhipinComItem()
            job_primary = job.css('div.job-primary')
            item['pid'] = job.css(
                'div.info-primary > h3 > a::attr(data-jobid)').extract_first().strip()
            
            #job-title这里和源码不同,页面改版所导致
            item['positionName'] = job_primary.css(
                'div.info-primary > h3 > a > div.job-title::text').extract_first().strip()
            item['salary'] = job_primary.css(
                'div.info-primary > h3 > a > span::text').extract_first().strip()
            #提取全部内容: .extract(),获得是一个列表
            #提取第一个:.extract_first(),获得是一个字符串
            info_primary = job_primary.css(
                'div.info-primary > p::text').extract()
            item['city'] = info_primary[0].strip()
            item['experience'] = info_primary[1].strip()
            item['educational'] = info_primary[2].strip()
            item['company'] = job_primary.css(
                'div.info-company > div.company-text > h3 > a::text').extract_first().strip()
            company_infos = job_primary.css(
                'div.info-company > div.company-text > p::text').extract()
            if len(company_infos)== 3:
                item['industryField'] = company_infos[0].strip()
                item['financeStage'] = company_infos[1].strip()
                item['companySize'] = company_infos[2].strip()
            
            #页面改版,已没有标签,所以这一段代码    
            item['positionLables'] = job.css(
                'li > div.job-tags > span::text').extract()
            
            #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格)或字符序列。
            #注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。
            #此处页面已改版,和源代码不同
            item['time'] = job_primary.css(
                'div.info-publis > p::text').extract_first().strip()
            
            item['updated_at'] = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
            yield item
            
        self.curPage += 1
        time.sleep(5) #爬的慢一点,免得被封ip
        yield self.next_request()
        
    def next_request(self):
        return scrapy.http.FormRequest(
            self.positionUrl + ("&page=%d&ka=page-%d" % 
                               (self.curPage, self.curPage)),
            headers=self.headers,
            callback=self.parse)

5.3 json数据汉化

还记得之前贴出来的item.json文件吗,全是英文和字符,按照这一步,重新爬取,将转换成汉字

Point 1 设置 UTF-8 编码
但是不巧,往往这是一个 Unicode 编码的文件,所以需要加个设置
在 settings.py中添加(PS:也可以在运行的时候带上这个参数)

FEED_EXPORT_ENCODING = 'utf-8'

重新爬取后

{"pid": "23200059", "positionName": "高级后端工程师(Python)", "salary": "20k-40k", "city": "北京", "experience": "3-5年", "educational": "本科", "company": "Kavout", "positionLables": [], "time": "发布于昨天", "updated_at": "2018-07-17 12:43:14"},
{"pid": "23199912", "positionName": "Python开发工程师", "salary": "12k-16k", "city": "北京", "experience": "3-5年", "educational": "本科", "company": "北京南天", "positionLables": [], "time": "发布于昨天", "updated_at": "2018-07-17 12:43:14"},

预告

下一篇,python爬虫实战(2) -- MongoDB和数据清洗

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容

  • 爬虫文章 in 简书程序员专题: like:128-Python 爬取落网音乐 like:127-【图文详解】py...
    喜欢吃栗子阅读 21,615评论 4 412
  • 以下文章转载自知乎,暗灭-京华九月秋近寒,浮沉半生影长单. 暗灭 京华九月秋近寒,浮沉半生影长单 10,850 人...
    ve追风_685b阅读 3,951评论 1 15
  • 1. 概述 本文主要介绍网络爬虫,采用的实现语言为Python,目的在于阐述网络爬虫的原理和实现,并且对目前常见的...
    Lemon_Home阅读 2,613评论 0 21
  • 不知不觉从0到1创业课已经上了六次课程,基本坚持了课程的学习,只要有空闲的时候就会不自觉地进行复习,今天我就...
    风兮勇者阅读 360评论 1 2
  • 2016年, 因为写作,因为出差,因为旅行,结识一帮妖孽,组成了一个微信群叫“有故事的人”。个个说起自己的人生都是...
    君子既来云胡不喜阅读 964评论 0 1