当前位置:   article > 正文

python3 scrapy实战:爬取拉勾网招聘数据至数据库(反爬虫)_头歌scrapy爬虫之拉勾网招聘数据分析

头歌scrapy爬虫之拉勾网招聘数据分析

首先注明:感谢拉勾网提供的权威、质量的数据,本人抱着学习的态度,不愿增加其服务器负担,与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源码:

  1. # -*- coding: utf-8 -*-
  2. import scrapy
  3. import json
  4. import time
  5. import os
  6. path = os.path.abspath(os.path.join(os.getcwd(), "../.."))
  7. import sys
  8. sys.path.append(path)
  9. from get_lagouwang.items import LagouItem
  10. import main
  11. class LagouwangSpider(scrapy.Spider):
  12. name = 'lagouwang'
  13. def __init__(self):
  14. 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'}
  15. self.cookie = {"user_trace_token":"20180526201245-0ea516fd-da30-4994-9995-5fa02a3eab36",
  16. "LGUID":"20180526201246-19bb1f81-60de-11e8-a18e-525400f775ce",
  17. "index_location_city":"%E5%85%A8%E5%9B%BD",
  18. "JSESSIONID":"ABAAABAABEEAAJAF96A0BE8427F1DD99F8C9B9EB6D7970D",
  19. "TG-TRACK-CODE":"search_code",
  20. "SEARCH_ID":"acc14cb01bbe44db9e430661bccdc92e",
  21. "_gid":"GA1.2.187875505.1527336770",
  22. "_ga":"GA1.2.467998237.1527336770",
  23. "Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6":"1527408192,1527408683,1527469793,1527486623",
  24. "Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6":"1527503666",
  25. "LGSID":"20180528183425-b12d579f-6262-11e8-ada5-525400f775ce",
  26. "PRE_UTM":"",
  27. "PRE_HOST":"",
  28. "PRE_SITE":"https%3A%2F%2Fwww.lagou.com%2F",
  29. "PRE_LAND":"https%3A%2F%2Fwww.lagou.com%2Fjobs%2Flist_%3FlabelWords%3D%26fromSearch%3Dtrue%26suginput%3D",
  30. "LGRID":"20180528183425-b12d59ef-6262-11e8-ada5-525400f775ce"
  31. }
  32. self.url = 'https://www.lagou.com/jobs/positionAjax.json?px=new&needAddtionalResult=false'
  33. self.total_page = 0
  34. self.first = 'true'
  35. self.kd = ''
  36. self.pn = 1
  37. def parse(self, response):
  38. item = LagouItem()
  39. data = json.loads(response.body)
  40. data_position = data['content']['positionResult']
  41. data_result = data_position['result']
  42. self.total_page = data_position['totalCount']
  43. for i in range(len(data_result)):
  44. item['salary'] = data_result[i]['salary']
  45. item['city'] = data_result[i]['city']
  46. item['workYear'] = data_result[i]['workYear']
  47. item['education'] = data_result[i]['education']
  48. item['industryField'] = data_result[i]['industryField']
  49. item['companySize'] = data_result[i]['companySize']
  50. item['positionName'] = data_result[i]['positionName']
  51. sal = data_result[i]['salary']
  52. sal = sal.split('-')
  53. if(len(sal)==1):
  54. item['salary_min'] = sal[0][:sal[0].find('k')]
  55. item['salary_max'] = sal[0][:sal[0].find('k')]
  56. else:
  57. item['salary_min'] = sal[0][:sal[0].find('k')]
  58. item['salary_max'] = sal[1][:sal[1].find('k')]
  59. yield item
  60. if(self.pn <= self.total_page):    #当前页数小于总页数,那么我们就继续请求下一页,再爬取
  61. print("pn:{} 运行中请勿打断...".format(self.pn+1))
  62. time.sleep(0.5)
  63. self.pn +=1
  64. 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)
  65. def start_requests(self):
  66. 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源码:

  1. import pymysql
  2. import re
  3. class GetLagouwangPipeline(object):
  4. def table_exists(self,con,table_name):    #这个函数用来判断数据库中是否存在此表,当然也可以不写,手动控制
  5. sql = "show tables;"    #sql语句
  6. con.execute(sql)
  7. tables = [con.fetchall()]
  8. table_list = re.findall('(\'.*?\')',str(tables))
  9. table_list = [re.sub("'",'',each) for each in table_list]
  10. if table_name in table_list:
  11. return 1
  12. else:
  13. return 0
  14. def process_item(self,item,spider):
  15. connect = pymysql.connect(
  16. user = 'root',
  17. password = 'root@123456',
  18. db = 'MYSQL',
  19. host = '127.0.0.1',
  20. port = 3306,
  21. charset = 'utf8'
  22. )
  23. con = connect.cursor()
  24. # con.execute("create database w_lagouwang")    #第一次使用需要创建数据库
  25. con.execute("use w_lagouwang")    #使用数据库
  26. table_name = 'lagouwang'        #表名
  27. if(self.table_exists(con,table_name) != 1):
  28. sql = '''create table lagouwang(city varchar(20),companySize varchar(20),education varchar(20),
  29. industryField varchar(30),positionName varchar(40),salary varchar(20),salary_max varchar(10),salary_min varchar(10),
  30. workYear varchar(20))'''
  31. con.execute(sql)    #创建数据库
  32. data = {'city':item['city'],'companySize':item['companySize'],'education':item['education'],
  33. 'industryField':item['industryField'],'positionName':item['positionName'],'salary':item['salary'],
  34. 'salary_max':item['salary_max'],'salary_min':item['salary_min'],'workYear':item['workYear']}
  35. city = data['city']
  36. companySize = data['companySize']       #提取item传来的值到对应的9个变量中
  37. education = data['education']
  38. industryField = data['industryField']
  39. positionName = data['positionName']
  40. salary = data['salary']
  41. salary_max = data['salary_max']
  42. salary_min = data['salary_min']
  43. workYear = data['workYear']            #保存到表中
  44. 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)',
  45. [city,companySize,education,industryField,positionName,salary,salary_max,salary_min,workYear])
  46. connect.commit()    #保存到数据库后记得需要提交
  47. con.close()        #关闭连接
  48. connect.close()
  49. return data

其实很简单的,就是sql语句有点多,和一个判断表的函数,真正的代码不多。

好了,接下来就是运行了,等等我们先配置一下setting文件:


记得开启setting中的ITEM_PIPELINES通道,否则通道不能使用。

接下来就可以运行了。。。


大致数据像上面,对于上面的数据我还做过一点处理,但是不影响上面的操作。

好了拉钩网反爬虫的项目就完成了,可以看出还是挺简单的,只是每一步都有需要细心,还有就是注意文件之间的关联性,其他的就没有了。反爬虫其实还有很多种,这里只是一种,在接下来的几篇文章中我还会介绍爬取 直聘网,猎聘网等,都有反爬虫机制。有问题的朋友可以留言交流。


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/654843
推荐阅读
相关标签
  

闽ICP备14008679号