拉勾网爬虫
解析拉勾网网站:
在拉勾网上输入关键词后我们可以得到相应的岗位信息(这里以Python为例),我们先获取到网站中所有的城市信息,再通过城市信息遍历爬取全国的Python职位信息。
在数据包的Headers中我们可以得到网页头的相关信息,如网页URL、请求方法、Cookies信息、用户代理等相关信息。
获取所有城市:
class CrawlLaGou(object):
def __init__(self):
# 使用session保存cookies信息
self.lagou_session = requests.session()
self.header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
}
self.city_list = ""
#获取城市
def crawl_city(self):
#使用正则表达式获取HTML代码中的城市名称
city_search = re.compile(r'www\.lagou\.com\/.*\/">(.*?)')
#网页URL
city_url = "https://www.lagou.com/jobs/allCity.html"
city_result = self.crawl_request(method="GET", url=city_url)
self.city_list = city_search.findall(city_result)
self.lagou_session.cookies.clear()
#返回结果
def crawl_request(self,method,url,data=None,info=None):
while True:
if method == "GET":
response = self.lagou_session.get(url=url,headers=self.header)
elif method == "POST":
response = self.lagou_session.post(url=url, headers=self.header, data=data)
response.encoding = "utf8"
return response.text
if __name__ == '__main__':
lagou = CrawlLaGou()
lagou.crawl_city()
print(lagou.city_list)
其中self.header中的User-Agent信息也在上图中Headers中可以找到。上述代码先将url所对应的网页源码爬取下来,再通过正则表达式获取到网页中的所有城市名称。
运行结果:
在我们获取完所有的城市名称信息后,我们开始获取城市对应的职位信息,我们回到职位列表(https://www.lagou.com/jobs/list_python),找到存放有职位信息的数据包,以及其对应的请求头部信息。
存放职位信息的数据包:
在得到网页的职位信息后,我们可以使用https://www.json.cn/进行解析,并找出我们需要的信息内容。
从json解析中,我们可以得到职位信息的列表为’content’→’positionResult’→’result’
获取职位信息:
#获取职位信息
def crawl_city_job(self,city):
#职位列表数据包的url
first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="%city
first_response = self.crawl_request(method="GET", url=first_request_url)
#使用正则表达式获取职位列表的页数
total_page_search = re.compile(r'class="span\stotalNum">(\d+)')
try:
total_page = total_page_search.search(first_response).group(1)
except:
# 如果没有职位信息,直接return
return
else:
for i in range(1, int(total_page) + 1):
#data信息中的字段
data = {
"pn":i,
"kd":"python"
}
#存放职位信息的url
page_url = "https://www.lagou.com/jobs/positionAjax.json?city=%s&needAddtionalResult=false" % city
#添加对应的Referer
referer_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="% city
self.header['Referer'] = referer_url.encode()
response = self.crawl_request(method="POST",url=page_url,data=data,info=city)
lagou_data = json.loads(response)
#通过json解析得到的职位信息存放的列表
job_list = lagou_data['content']['positionResult']['result']
for job in job_list:
print(job)
在上述代码中,先通过存放职位列表的数据包url(first_request_url)中获取网页代码中的页码信息,并通过页码来判断是否存在岗位信息,若没有则返回。若有,则通过存放职位信息的数据包url(page_url),并添加对应的data数据和Refer信息,来获取该数据包中的所有信息,最后通过’content’→’positionResult’→’result’的列表顺序来获得到我们所需要的职位信息。
运行结果:
解决“操作太频繁,请稍后再试”的问题:
如在爬虫运行过程中出现“操作太频繁”则说明该爬虫已经被网站发现,此时我们需要清除cookies信息并重新获取该url,并让程序停止10s后再继续运行。
#返回结果
def crawl_request(self,method,url,data=None,info=None):
while True:
if method == "GET":
response = self.lagou_session.get(url=url,headers=self.header)
elif method == "POST":
response = self.lagou_session.post(url=url, headers=self.header, data=data)
response.encoding = "utf8"
#解决操作太频繁问题
if '频繁' in response.text:
print(response.text)
self.lagou_session.cookies.clear()
first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput=" % info
self.crawl_request(method="GET", url=first_request_url)
time.sleep(10)
continue
return response.text
将爬取到的数据保存到数据库:
在以上我们爬取到的结果中,我们只是爬取了在result列表中的所有数据,可读性还比较差。我们需要创建一个数据库,并筛选出我们需要的数据插入进去。
#创建数据库连接
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/lagou?charset=utf8")
#操作数据库
Session = sessionmaker(bind=engine)
#声明一个基类
Base = declarative_base()
class Lagoutables(Base):
#表名称
__tablename__ = 'lagou_java'
#id,设置为主键和自动增长
id = Column(Integer,primary_key=True,autoincrement=True)
#职位id
positionID = Column(Integer,nullable=True)
# 经度
longitude = Column(Float, nullable=False)
# 纬度
latitude = Column(Float, nullable=False)
# 职位名称
positionName = Column(String(length=50), nullable=False)
# 工作年限
workYear = Column(String(length=20), nullable=False)
# 学历
education = Column(String(length=20), nullable=False)
# 职位性质
jobNature = Column(String(length=20), nullable=True)
# 公司类型
financeStage = Column(String(length=30), nullable=True)
# 公司规模
companySize = Column(String(length=30), nullable=True)
# 业务方向
industryField = Column(String(length=30), nullable=True)
# 所在城市
city = Column(String(length=10), nullable=False)
# 岗位标签
positionAdvantage = Column(String(length=200), nullable=True)
# 公司简称
companyShortName = Column(String(length=50), nullable=True)
# 公司全称
companyFullName = Column(String(length=200), nullable=True)
# 工资
salary = Column(String(length=20), nullable=False)
# 抓取日期
crawl_date = Column(String(length=20), nullable=False)
插入数据:
def __init__(self):
self.mysql_session = Session()
self.date = time.strftime("%Y-%m-%d",time.localtime())
#数据存储方法
def insert_item(self,item):
#今天
date = time.strftime("%Y-%m-%d",time.localtime())
#数据结构
data = Lagoutables(
#职位ID
positionID = item['positionId'],
# 经度
longitude=item['longitude'],
# 纬度
latitude=item['latitude'],
# 职位名称
positionName=item['positionName'],
# 工作年限
workYear=item['workYear'],
# 学历
education=item['education'],
# 职位性质
jobNature=item['jobNature'],
# 公司类型
financeStage=item['financeStage'],
# 公司规模
companySize=item['companySize'],
# 业务方向
industryField=item['industryField'],
# 所在城市
city=item['city'],
# 职位标签
positionAdvantage=item['positionAdvantage'],
# 公司简称
companyShortName=item['companyShortName'],
# 公司全称
companyFullName=item['companyFullName'],
# 工资
salary=item['salary'],
# 抓取日期
crawl_date=date
)
#在存储数据之前查询表里是否有这条职位信息
query_result = self.mysql_session.query(Lagoutables).filter(Lagoutables.crawl_date==date,
Lagoutables.positionID == item['positionId']).first()
if query_result:
print('该职位信息已存在%s:%s:%s' % (item['positionId'], item['city'], item['positionName']))
else:
#插入数据
self.mysql_session.add(data)
#提交数据
self.mysql_session.commit()
print('新增职位信息%s' % item['positionId'])
运行结果:
此时职位信息已保存到数据库中:
完整代码:
github:https://github.com/KeerZhou/crawllagou
csdn:https://download.csdn.net/download/keerzhou/11584694