赞
踩
首先注明:感谢拉勾网提供的权威、质量的数据,本人抱着学习的态度,不愿增加其服务器负担,与dos攻击。
由于后面准备做一个大一点的数据分析项目,所以前提需要获取大量的有质量和权威的信息,其中一个获取点便是拉钩网,进入正题:
本片将介绍对拉钩网的招聘数据爬取,过程中包括了反爬虫post请求来获取数据文件。以及将所有的信息,保存到MySQL数据库中。
首先我们来分析一下我们需要爬取信息的网页信息:
https://www.lagou.com/jobs/list_?labelWords=&fromSearch=true&suginput=
下面这个招聘信息就是我们后面要获取的信息,获取的内容包括(城市、规模、学历、领域、职位、薪水、工作经验等7个内容)
但是我们马上就会发现下面这个问题:
这只有一页信息,当我们换页时,发现它并没有加载网页,而是直接就出来了,那不是就没法爬取更多的信息了吗,只有一页。这便是该网页的一个反爬虫措施,这是属于异步加载的网页,这里就不多讲它了。我们来获取数据
点击F12开发调试工具,选中Network,再点F5刷新网页,可以看到有很多的数据包出来了:
这些就是网页传输时的数据包(当然也可以使用fiddler这样的抓包工具来抓),一个小技巧,大部分网页传输的内容信息包含在后缀名为json的文件里,所以这里我们在上面输入json来过滤包,仔细查看并选中可能包含有传输数据的包,再打开它:
查看Response找到是否包含我们的数据:
在Preview中我们可以结构化的查看数据包。
找到信息后我们就要思考如何才能够拿到这些数据了。这样的数据一般都是post请求,我们查看Headers寻找信息:
在Heasers里面我们发现两个数据格式:Query string parameters和Form data,第一个是get请求明文附在请求链接上面的信息,后面的是post请求需要匿名传输的。
右键数据包,然后拷贝下它的链接,这个链接包含了明文信息,无需我们手动附加(你可以点击open link in new tab,应该是操作频繁),接着我们只需要post请求并传输匿名信息来获取数据包了。
在此之前我们先分析一下匿名传输信息到底代表什么意思哈:
上面的图可以看到有三个信息:first、pd、kd,其中first=True我也不是太明白意义,大概是为真吧;接着pd,这个很好理解page number页数;接着kd,key words关键字,也就是你要搜索的关键字,为空表示内容不限。这都是我个人的理解,应该差不多吧。
好了,所有的准备工作都做完了,现在就开始scrapy框架的爬取。
创建scrapy这里就不累述了(太基础的可以先去了解一下,以及需要了解一下scrapy的工作原理):
我们先编写容器文件,以便确定我们需要获取的信息(这里我在items里面新建的类,也可以使用原来的):
接着我们来编写spider文件:
spider源码:
- # -*- coding: utf-8 -*-
- import scrapy
- import json
- import time
- import os
- path = os.path.abspath(os.path.join(os.getcwd(), "../.."))
- import sys
- sys.path.append(path)
- from get_lagouwang.items import LagouItem
- import main
-
-
- class LagouwangSpider(scrapy.Spider):
- name = 'lagouwang'
-
- def __init__(self):
- self.headers = {'Referer':'https://www.lagou.com/jobs/list_?city=%E5%85%A8%E5%9B%BD&cl=false&fromSearch=true&labelWords=&suginput=','User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0'}
- self.cookie = {"user_trace_token":"20180526201245-0ea516fd-da30-4994-9995-5fa02a3eab36",
- "LGUID":"20180526201246-19bb1f81-60de-11e8-a18e-525400f775ce",
- "index_location_city":"%E5%85%A8%E5%9B%BD",
- "JSESSIONID":"ABAAABAABEEAAJAF96A0BE8427F1DD99F8C9B9EB6D7970D",
- "TG-TRACK-CODE":"search_code",
- "SEARCH_ID":"acc14cb01bbe44db9e430661bccdc92e",
- "_gid":"GA1.2.187875505.1527336770",
- "_ga":"GA1.2.467998237.1527336770",
- "Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6":"1527408192,1527408683,1527469793,1527486623",
- "Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6":"1527503666",
- "LGSID":"20180528183425-b12d579f-6262-11e8-ada5-525400f775ce",
- "PRE_UTM":"",
- "PRE_HOST":"",
- "PRE_SITE":"https%3A%2F%2Fwww.lagou.com%2F",
- "PRE_LAND":"https%3A%2F%2Fwww.lagou.com%2Fjobs%2Flist_%3FlabelWords%3D%26fromSearch%3Dtrue%26suginput%3D",
- "LGRID":"20180528183425-b12d59ef-6262-11e8-ada5-525400f775ce"
- }
- self.url = 'https://www.lagou.com/jobs/positionAjax.json?px=new&needAddtionalResult=false'
- self.total_page = 0
- self.first = 'true'
- self.kd = ''
- self.pn = 1
-
- def parse(self, response):
- item = LagouItem()
- data = json.loads(response.body)
- data_position = data['content']['positionResult']
- data_result = data_position['result']
- self.total_page = data_position['totalCount']
- for i in range(len(data_result)):
- item['salary'] = data_result[i]['salary']
- item['city'] = data_result[i]['city']
- item['workYear'] = data_result[i]['workYear']
- item['education'] = data_result[i]['education']
- item['industryField'] = data_result[i]['industryField']
- item['companySize'] = data_result[i]['companySize']
- item['positionName'] = data_result[i]['positionName']
- sal = data_result[i]['salary']
- sal = sal.split('-')
- if(len(sal)==1):
- item['salary_min'] = sal[0][:sal[0].find('k')]
- item['salary_max'] = sal[0][:sal[0].find('k')]
- else:
- item['salary_min'] = sal[0][:sal[0].find('k')]
- item['salary_max'] = sal[1][:sal[1].find('k')]
- yield item
- if(self.pn <= self.total_page): #当前页数小于总页数,那么我们就继续请求下一页,再爬取
- print("pn:{} 运行中请勿打断...".format(self.pn+1))
- time.sleep(0.5)
- self.pn +=1
- yield scrapy.http.FormRequest(self.url,cookies=self.cookie,headers=self.headers,formdata={'first':self.first,'kd':self.kd,'pn':str(self.pn)},callback=self.parse)
-
- def start_requests(self):
- return [scrapy.http.FormRequest(self.url,cookies=self.cookie,headers=self.headers,formdata={'first':self.first,'kd':self.kd,'pn':str(self.pn)},callback=self.parse)]
注意这里我设置了cookie和headers,在post请求时一同传输的,伪造浏览器的信息,防止网站封IP。在Headers可以获取:
将里面的信息,获取到。这些信息有点多,在上面的代码中,其实真正的内容并不多。
首先我们使用start_requests来请求第一页信息,返回至parse函数中,然后在parse中通过判断当前页数,来确定是否继续爬取网页。需要注意的上面的文件中我们导入了之前创建的容器类LagouItem()。os.path.abspath是我用来导入上上层文件的路径,sys.path我用来添加main.py和items.py文件的路径,main.py中,就是执行scraoy的命令,你也可以在cmd中执行scrapy,我之前的文章有介绍很方便的。spider很简单,代码不多,我们介绍pipelines文件。
现在我们只是爬取到了文件,但是并没有保存它,我们可以将信息保存为csv文件或其他格式,这里我们使用MySQL数据库来存储。所以我们要编写pipelines文件,在里面利用item容器每次存入后传递过来的值。
pipelines源码:
- import pymysql
- import re
-
- class GetLagouwangPipeline(object):
-
- def table_exists(self,con,table_name): #这个函数用来判断数据库中是否存在此表,当然也可以不写,手动控制
- sql = "show tables;" #sql语句
- con.execute(sql)
- tables = [con.fetchall()]
- table_list = re.findall('(\'.*?\')',str(tables))
- table_list = [re.sub("'",'',each) for each in table_list]
- if table_name in table_list:
- return 1
- else:
- return 0
-
- def process_item(self,item,spider):
- connect = pymysql.connect(
- user = 'root',
- password = 'root@123456',
- db = 'MYSQL',
- host = '127.0.0.1',
- port = 3306,
- charset = 'utf8'
- )
- con = connect.cursor()
- # con.execute("create database w_lagouwang") #第一次使用需要创建数据库
- con.execute("use w_lagouwang") #使用数据库
- table_name = 'lagouwang' #表名
- if(self.table_exists(con,table_name) != 1):
- sql = '''create table lagouwang(city varchar(20),companySize varchar(20),education varchar(20),
- industryField varchar(30),positionName varchar(40),salary varchar(20),salary_max varchar(10),salary_min varchar(10),
- workYear varchar(20))'''
- con.execute(sql) #创建数据库
- data = {'city':item['city'],'companySize':item['companySize'],'education':item['education'],
- 'industryField':item['industryField'],'positionName':item['positionName'],'salary':item['salary'],
- 'salary_max':item['salary_max'],'salary_min':item['salary_min'],'workYear':item['workYear']}
- city = data['city']
- companySize = data['companySize'] #提取item传来的值到对应的9个变量中
- education = data['education']
- industryField = data['industryField']
- positionName = data['positionName']
- salary = data['salary']
- salary_max = data['salary_max']
- salary_min = data['salary_min']
- workYear = data['workYear'] #保存到表中
- con.execute('insert into lagouwang(city,companySize,education,industryField,positionName,salary,salary_max,salary_min,workYear)values(%s,%s,%s,%s,%s,%s,%s,%s,%s)',
- [city,companySize,education,industryField,positionName,salary,salary_max,salary_min,workYear])
- connect.commit() #保存到数据库后记得需要提交
- con.close() #关闭连接
- connect.close()
- return data
-
其实很简单的,就是sql语句有点多,和一个判断表的函数,真正的代码不多。
好了,接下来就是运行了,等等我们先配置一下setting文件:
记得开启setting中的ITEM_PIPELINES通道,否则通道不能使用。
接下来就可以运行了。。。
大致数据像上面,对于上面的数据我还做过一点处理,但是不影响上面的操作。
好了拉钩网反爬虫的项目就完成了,可以看出还是挺简单的,只是每一步都有需要细心,还有就是注意文件之间的关联性,其他的就没有了。反爬虫其实还有很多种,这里只是一种,在接下来的几篇文章中我还会介绍爬取 直聘网,猎聘网等,都有反爬虫机制。有问题的朋友可以留言交流。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。