Python | 数据分析实战Ⅰ

Linux之父Linus

“Talk is cheap,Show me the code.”翻译为中文是“废话少说,放码过来。”我以为可谓信达雅。javascript

在编程之路上,实践的重要性无可比拟。这也是不少同窗感受学了不少,但仍是不会写代码的缘由;也是不少有意转行的人士,自学了大半年,仍不见转机的缘故。java

leoxin在知识星球发起一项活动:目标是爬取拉钩网的招聘信息以及链家的房产信息,而后对数据进行清洗和存储,并分析其数据下的价值,最后用可视化的形式表现出来。 我以为难度适中,按部就班,对于不一样身份角色的学习人群都大有裨益。git

下面我来写一写在第一阶段的一些学习操做总结和感觉。web

爬虫

构思/准备部分

首先打开拉钩网,我初步选择的是Java-上海 编程

Step1

打开浏览器开发者工具,观察Network部分的内容,首先点进Doc部分,看看服务器给咱们返回了哪些文本内容。json

在Preview预览中,咱们能够看到,大部分都是一些公共视图框架和公共JS代码,没有核心数据。数组

那么这时咱们就应该猜想,网站多是首先渲染一个公共框架,而后再经过Ajax发送请求去得到数据,再在页面上显示获取的数据。 浏览器

doc

Step2

经过Step1的思考和猜想,大体肯定了数据是异步获取的。作过一点web的应该都想获得这一点,由于即便是反爬,也要按照基本法啊!应该不会使用多么多么匪夷所思的黑科技(若是真的出现了,那是我太菜了的缘由(っ °Д °;)っ)bash

这时点开XHR按钮,XHR全称XMLHttpRequest,有什么做用呢?Ajax经过XMLHttpRequest对象发出HTTP请求,获得服务器返回的数据。服务器

经过预览咱们能够发现,咱们须要的数据都出如今positionAjax请求下返回的数据中,参见content-positionResult-result中。

那么该如何伪造请求?

点进Headers,首先发现Request Method的值是POST,肯定了咱们提交请求的方式。而后看看Request Headers中的字段。

发现有好多条。

Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.9
Connection:keep-alive
Content-Length:23
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Cookie:XXX
Host:www.lagou.com
Origin:https://www.lagou.com
Referer:https://www.lagou.com/jobs/list_Java?px=default&city=%E4%B8%8A%E6%B5%B7
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
X-Anit-Forge-Code:0
X-Anit-Forge-Token:None
X-Requested-With:XMLHttpRequest
复制代码

经过筛选,咱们选取其中有用的几条,构建本身的请求头。(那么怎么知道哪些是有用的呢?首先筛除语言,编码之类的,这些的影响通常都是比较小的;接着在剩下的字段中进行尝试,等之后有经验了,天然能准确选取有价值的字段)

因为是POST的请求方式,那么势必会向服务器提交一些数据,能够看到表单信息:

first:true
pn:1
kd:Java
复制代码

xhr
headers

实现/代码部分

Step1

在进行上述分析后,基本已经准备得差很少了。这时能够先简单构建一下咱们的Proxy类。

class Proxy():
    def __init__(self):
        self.MAX=5 #最大嗅探次数
        self.headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
            "Referer":"https://www.lagou.com/jobs/list_Java?px=default&city=%E4%B8%8A%E6%B5%B7",
            "X-Anit-Forge-Code":"0",
            "X-Anit-Forge-Token":"None",
            "X-Requested-With":"XMLHttpRequest"
        }

    def getPage(self,url,data):
        FAILTIME=0 #访问失败次数
        try:
            result=requests.post(url,headers=self.headers,data=data)
            result.encoding = "utf-8"
            return result
        except:
            FAILTIME+=1
            if FAILTIME==self.MAX:
                print("访问错误")
                return ''

复制代码

上文中提到,发现Ajaxposition返回的content-positionResult-result数据,数据格式是一个数组里有15条数据,每条数据的格式是一个字典,具体以下:

adWord:9
appShow:0
approve:1
businessZones:["唐镇", "唐镇", "曹路", "曹路"]
city:"上海"
companyFullName:"招商银行股份有限公司信用卡中心"
companyId:6796
companyLabelList:["金融科技银行", "技术创新驱动", "奋斗独立改变", "一年两次调薪"]
companyLogo:"i/image2/M00/25/D7/CgoB5lodmL2AJHxrAABieRjcJjU514.png"
companyShortName:"招商银行信用卡中心"
companySize:"2000人以上"
createTime:"2018-03-09 09:14:30"
deliver:0
district:"浦东新区"
education:"本科"
explain:null
financeStage:"上市公司"
firstType:"开发/测试/运维类"
formatCreateTime:"09:14发布"
gradeDescription:null
hitags:null
imState:"today"
industryField:"移动互联网,金融"
industryLables:[]
isSchoolJob:0
jobNature:"全职"
lastLogin:1520581074000
latitude:"31.247248"
linestaion:null
longitude:"121.673868"
pcShow:0
plus:null
positionAdvantage:"五险一金,职位晋升,各种补贴"
positionId:2762378
positionLables:["项目管理", "j2ee", "架构"]
positionName:"Java技术经理"
promotionScoreExplain:null
publisherId:73936
resumeProcessDay:1
resumeProcessRate:100
salary:"30k-50k"
score:0
secondType:"管理岗"
stationname:null
subwayline:null
workYear:"5-10年"

复制代码

可见返回了大量的信息,那么咱们如何去得到这些数据?此时能够写一个简单的Job类:

class Job:
    def __init__(self):
        self.datalist=[]

    def getJob(self,url,data):
        p=Proxy()
        result=p.getPage(url,data)
        result.encoding = "utf-8"
        result_dict=result.json()
        try:
            job_info = result_dict['content']['positionResult']['result']
            for info in job_info:
                print(info)
            return job_info
        except:
            print("发生解析错误")
       
复制代码

使用getJob方法获取的是全部的信息,这实际上是没必要要的,应该也有所选择,不然将给本身带来压力,对于后续步骤也将带来不便。

Step2

此时,一个简单的爬虫已经编写得差很少了,咱们能够进行测试一下。 编写主函数

if __name__ == '__main__':
    url="https://www.lagou.com/jobs/positionAjax.json?px=default&city=%E4%B8%8A%E6%B5%B7&needAddtionalResult=false&isSchoolJob=0"
    job = Job()
    all_page_info=[]
    for x in range(1,31):
        data = {
            "first": "false",
            "pn": x,
            "kd": "Java"
        }
        current_page_info=job.getJob(url,data)
        all_page_info.extend(current_page_info)
        print("第%d页已经爬取成功"%x)
        time.sleep(5)
复制代码

能够看到控制台显示:

总结

到这里,一个简单的爬虫已经编写完毕了,数据以json格式返回,彷佛已经大功告成。而事实是,对于为后面的数据分析作准备工做还差得远,对于爬取海量数据,下面有几点思考。

  • 拉钩网对于同一ip的大量请求行为确定会进行封禁,因此须要准备代理池。
  • 为了实现高自动化,须要对一系列可能出现的异常状况进行处理,断点处理,确保程序不挂。
  • 为了提升效率,加入多线程。
  • 数据持久化,在持久化以前须要先进行清洗。
  • ......

针对以上问题,须要进一步学习。

扫一扫,关注公众号
相关文章
相关标签/搜索