赞
踩
1、网易招聘
1.1 问题梳理
(1)该网站是一个JSON数据渲染的动态网页,网页源码里面并没有数据,这个地方不能直接用Xpath解析。
(2)打开这个页面一共有2856个职位,有286页,因此需要翻页。
(3)爬取的数据信息要保存到Mysql数据库,写一个通用的数据库的类进行保存。
2、页面分析(这个是关键,找到这个请求页面动态加载JSON数据的请求)
这就是json数据格式,里面的信息都包含了,因此就不需要通过每一个职位的详情页面链接再次获取相关的信息,后面的案例会有。
因此start_url页面的地址就不是第一个地址了,而且请求的方式为POST请求,带有相关的参数。相关参数见Payload
下面是在job.py构建的POST请求函数,keyword大家可以去掉,我这里只是学习,不想爬取太多的信息,因此用关键字Python限制了下,就相当于,我这里只是获取有关Python的职位信息。小伙伴们重点关注下yield scrapy.Request()里面的POST请求的写法。这里将请求获得的结果送给parse()函数进一步处理。
start_urls = ["https://hr.163.com/api/hr163/position/queryPage"]
def start_requests(self):
url = self.start_urls[0]
print(url)
# 起始url参数
payload = {
"currentPage": "1",
"keyword":"Python",
"pageSize": "10"
}
print(json.dumps(payload))
# 构建post请求
yield scrapy.Request(
url=url,
body=json.dumps(payload),
method='POST',
callback=self.parse,
headers={'Content-Type': 'application/json'}
)
3、相关代码
3.1 items.py
- import scrapy
- class WangyinewItem(scrapy.Item):
- # define the fields for your item here like:
- # name = scrapy.Field()
- name = scrapy.Field()
- productName = scrapy.Field()
- postTypeFullName = scrapy.Field()
- description = scrapy.Field()
- recruitNum = scrapy.Field()
- reqEducationName = scrapy.Field()
- reqWorkYearsName = scrapy.Field()
- requirement = scrapy.Field()
- firstPostTypeName = scrapy.Field()
- workPlaceNameList = scrapy.Field()
- #下面2个变量主要是为了做通用的数据库表写入程序用的。
- table_fields = scrapy.Field() # 字段名称
- table_name = scrapy.Field() # 插入表的名称
-
3.2 job.py
- import scrapy
- from wangyinew.items import WangyinewItem
- import json
-
- next_page =1 #用来控制翻页的变量,主要是给URL传递参数
- class JobSpider(scrapy.Spider):
- name = "job"
- allowed_domains = ["163.com"]
- #start_urls = ["https://hr.163.com/job-list.html"]
- start_urls = ["https://hr.163.com/api/hr163/position/queryPage"]
-
- def __init__(self):
- self.table_name = 'wangyijob'
- self.table_fields = ['name','productName','postTypeFullName','description','recruitNum',
- 'reqEducationName','reqWorkYearsName','requirement','firstPostTypeName','workPlaceNameList']
-
-
- def start_requests(self):
- url = self.start_urls[0]
- print(url)
- # 起始url参数
- payload = {
- "currentPage": "1",
- "keyword":"Python",
- "pageSize": "10"
- }
- print(json.dumps(payload))
- # 构建post请求
- yield scrapy.Request(
- url=url,
- body=json.dumps(payload),
- method='POST',
- callback=self.parse,
- headers={'Content-Type': 'application/json'}
- )
-
- def parse(self, response):
- dic = response.json()
- job_list = dic['data']['list']
- item = WangyinewItem()
- item['table_fields'] = self.table_fields
- item['table_name'] = self.table_name
- for job in job_list:
- item['name'] = job['name']
- item['productName'] = job['productName']
- item['postTypeFullName'] = job['postTypeFullName']
- item['description'] = job['description'].replace('\t','').replace('\n','')
- item['recruitNum'] = job['recruitNum']
- item['reqEducationName'] = job['reqEducationName']
- item['reqWorkYearsName'] = job['reqWorkYearsName']
- item['requirement'] = job['requirement'].replace('\t','').replace('\n','')
- item['firstPostTypeName'] = job['firstPostTypeName']
- item['workPlaceNameList'] = str(job['workPlaceNameList']).replace('[','').replace(']','').replace("'",'')
- # 处理数据
- yield item
-
- #模拟翻页
- # 返回的数据中来判断是否为最后一页 true为最后一页
- page_stutas = dic['data']['lastPage']
- global next_page
- next_page = next_page + 1
- print(next_page)
- if page_stutas == False: # 回调出口
- payload = {
- "currentPage":"{}".format(next_page),
- "keyword":"Python",
- "pageSize": "10"
- }
- print(payload)
- url = self.start_urls[0]
- yield scrapy.Request(
- url=url,
- body=json.dumps(payload),
- method='POST',
- callback=self.parse,
- headers={'Content-Type':'application/json'}
- )
我写代码的解释部分较少,如果有看不明白的小伙伴留言。
4、mysql数据库
MySQL是一种开源的关系型数据库管理系统,它采用了客户机-服务器模式,通过在服务器上存储数据并管理数据来提供数据管理服务。它支持多用户使用,并且能够高效地处理大量数据,被广泛应用于Web应用程序的开发、数据存储和数据分析等领域。MySQL使用SQL语言进行数据的管理和查询,并且具有高度灵活性、可移植性和可扩展性。它可以运行在各种操作系统上,包括Windows、Linux、Unix等。MySQL的特点是速度快、可靠性高、易学易用、易扩展等。
我用的mysql数据库是5.7经典解压版的,现在已经更新到Mysql8,我没有用安装包安装,小伙伴们可以自己选择下载安装,这玩意最好一次装好,如果报错,再次安装仍然出现问题,非常麻烦,除非重装系统,如果不幸的话叫我说中了,可以通过虚拟机安装mysql解决。
装好mysql配置环境变量,修改密码这一套还是很麻烦的。网上有教程。mysql-5.7.37-winx64解压版安装超详细图文教程_浩瀚之水_csdn的博客-CSDN博客
不出意外的话,我也是用navicat for Mysql软件进行数据库管理。
一顿操作猛如虎,在建个表用来保存数据,建表的命令在数据库下面的查询里面新建个查询,输入SQL语句的。这个我就不再赘述了,以后有机会再聊。
建表的SQL语句:(这个代码不是放到Python代码的,大家也可以通过函数来实现比较简单,我这没有写,小伙伴可以根据我给的代码组装下就OK了,不过每次运行的时候如果已经创建表了,就加个判断或异常即可)
- import pymysql
-
- def sqlexe(sql):
- db = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123456', database='mydb', charset='utf8')
- cursor = db.cursor()
- cursor.execute(sql)
- sqlret = cursor.fetchall()
- # col_result = cursor.description
- cursor.close()
- db.close()
- return sqlret
-
- CREATE TABLE `wangyijob` (
- `name` varchar(255) NOT NULL ,
- `productName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `postTypeFullName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `recruitNum` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `reqEducationName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `reqWorkYearsName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `requirement` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `firstPostTypeName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
- `workPlaceNameList` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
- )
说了这么多,最后放pipelines文件的代码,如果有什么格式问题,大家自己调整,本学习系列并非基础面向小白来的,如果有机会,我再详细讲解遇到的一些坑坑洼洼。
- from itemadapter import ItemAdapter
- import pymysql
- import logging
-
- class WangyinewPipeline:
- """
- 同步插入数据库
- """
- def __init__(self):
- self.connect=pymysql.connect(host='localhost',user='root',passwd='123456',db='mydb',charset='utf8',port=3306)
- self.cursor=self.connect.cursor()
-
- def process_item(self, item, spider):
- table_fields = item.get('table_fields')
- table_name = item.get('table_name')
- if table_fields is None or table_name is None:
- raise Exception('必须要传表名table_name和字段名table_fields,表名或者字段名不能为空')
- values_params = '%s, ' * (len(table_fields) - 1) + '%s'
- keys = ', '.join(table_fields)
- values = ['%s' % str(item.get(i, '')) for i in table_fields]
- insert_sql = 'insert into %s (%s) values (%s)' % (table_name, keys, values_params)
- try:
- self.cursor.execute(insert_sql, tuple(values))
- logging.info("数据插入成功 => " + '1')
- except Exception as e:
- logging.error("执行sql异常 => " + str(e))
- pass
- finally:
- # 要提交,不提交无法保存到数据库
- self.connect.commit()
- return item
-
- def close_spider(self, spider):
- self.connect.close()
- self.cursor.close()
5、最后上配置文件,这个比较简单。
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 填写下自己浏览器的USER_AGENT,尽量不要注释掉,有些网站没有这个请求参数,服务器不返回响应 ROBOTSTXT_OBEY = False # Obey robots.txt rules,这个爬虫协议对于我们这种桀骜不驯,不羁放纵爱自由的人来说,肯定不能遵守。
COOKIES_DEBUG = True
LOG_LEVEL = 'WARNING'只显示警告以上级别的信息,如果想看日志的小伙伴就给注释掉。掉。DOWNLOAD_DELAY = 1 建议大家每次都设置下延时,看看效果,如果慢可以关闭,但是如果关闭,服务器可能会识别过于频繁的请求,认为是爬虫程序,从而封禁IP。
最后把管道打开,让数据源源不断的流入数据库。
本案例仅供学习使用GitHub - wangluixn/scrapy_neteasejob
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。