当前位置: 首页>编程语言>正文

python爬虫数据清洗用什么工具 爬虫数据清洗的方法

实验内容:讲爬取的boss直聘岗位信息放入MongoDB中,清洗数据

环境

MAC book air

MongoDB 3.4.7 数据库

MongoBooster 4.6.1 数据库可视化工具

0 安装MongoDB

pip install pymongo

今天用pip和canda安装了pymongo,但是不会用 /哭

命令行敲mongo还是pymongo都不行

又找不到bin文件安装目录(/usr/local/mongodb/bin下面没有!),折腾了两个小时,气死了

最后用curl去官网down安装包,采用安装包方式安装,这样我才能知道装在哪个文件夹下面

墙外慢悠悠下载中。。。

今天先睡了,这个坑留到明天吧

————

用curl的方式安装成功,真不容易,方式如下

(官网下载MongoDB很慢,我提供一个下载链接

mongodb-osx-x86_64-3.4.7

链接: https://pan.baidu.com/s/1VPZap-u_3LWoVVtwC9CEFg 密码: 6h4y)

接下来我们使用 curl 命令来下载安装:

# 进入 /usr/local

cd /usr/local

# 下载

sudo curl -O https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.4.2.tgz

# 解压

sudo tar -zxvf mongodb-osx-x86_64-3.4.2.tgz

# 重命名为 mongodb 目录

sudo mv mongodb-osx-x86_64-3.4.2 mongodb

安装完成后,我们可以把 MongoDB 的二进制命令文件目录(安装目录/bin)添加到 PATH 路径中:

export PATH=/usr/local/mongodb/bin:$PATH

运行 MongoDB

1、首先我们创建一个数据库存储目录 /data/db:

sudo mkdir -p /data/db
启动 mongodb,默认数据库目录即为 /data/db:
sudo mongod
# 如果没有创建全局路径 PATH,需要进入以下目录
cd /usr/local/mongodb/bin
sudo ./mongod

再打开一个终端进入执行以下命令:

$ cd /usr/local/mongodb/bin
$ ./mongo
MongoDB shell version v3.4.2
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.2
Welcome to the MongoDB shell.
……
> 1 + 1
2
>

注意:如果你的数据库目录不是/data/db,可以通过 --dbpath 来指定。

1 导入职位数据到MongoDB中

1.1 通过./mongoimport命令导入数据(pwd是你的mongo安装路径)

#开启数据库后台服务,指定数据库位置,以及打印日志位置

#注意是在超级用户权限下

sh-3.2# ./mongod --dbpath /Users/limingxuan/Documents/GitHub/py03_web_crewler_advanced/www_zhipin_com/data/db/ --logpath /Users/limingxuan/Documents/GitHub/py03_web_crewler_advanced/www_zhipin_com/data/db/log --fork

about to fork child process, waiting until server is ready for connections.

forked process: 15370

child process started successfully, parent exiting

#将职位数据item.json导入数据库中

sh-3.2# ./mongoimport --db zhipin_jobs --collection Python_jobs --file /Users/limingxuan/Documents/GitHub/py03_web_crewler_advanced/www_zhipin_com/item.json --jsonArray

2018-07-20T07:48:36.889+0800 connected to: localhost

2018-07-20T07:48:36.955+0800 imported 30 documents

1.2数据库可视化

打开MongoBooster,连接数据库mongodb://127.0.0.1:27017

可以看到已经导入进去的数据

导入的30条职位信息

MongoDB常用命令

show dbs 显示所有数据库

show collections 显示数据库中的集合(类似关系数据库中的表)

db.dropDatabase() 删除当前使用的数据库

use 切换当前数据库

02 爬取岗位介绍和要求

2.1 获取岗位详情页面链接

因此这一步先根据数据库中每条数据的pid取出data-jid,插入链接中

获得岗位详情页面链接

以下是我抓取的结果,都可以打开连接

import requests
cs_url = 'http://httpbin.org'
r = requests.get("%s/%s" % (cs_url, 'get'))
r = requests.post("%s/%s" % (cs_url, 'post'))
r = requests.put("%s/%s" % (cs_url, 'put'))
r = requests.delete("%s/%s" % (cs_url, 'delete'))
r = requests.patch("%s/%s" % (cs_url, 'patch'))
r = requests.options("%s/%s" % (cs_url, 'get'))

https://liam0205.me/2016/02/27/The-requests-library-in-Python/

当我们使用 requests.* 发送请求时,Requests 做了两件事:

构建一个 Request 对象,该对象会根据请求方法或相关参数发起 HTTP 请求

一旦服务器返回响应,就会产生一个 Response 对象,该响应对象包含服务器返回的所有信息,也包含你原来创建的 Request 对象

对于响应状态码,我们可以访问响应对象的 status_code 属性:

import requests
r = requests.get("http://httpbin.org/get")
print r.status_code
# 输出
200

对于响应正文,我们可以通过多种方式读取,比如:

普通响应,使用 r.text 获取

JSON 响应,使用 r.json() 获取

二进制响应,使用 r.content 获取

原始响应,使用 r.raw 获取

参考:http://funhacks.net/explore-python/HTTP/Requests.html

小知识:

对于python代码中的if __name__ == '__main__'

我们简单的理解就是: 如果模块是被直接运行的,则代码块被运行,如果模块是被导入的,则代码块不被运行。

2.2 爬取详情页中的岗位介绍和要求

大致流程如下:

从代码中取出pid

根据pid拼接网址 => 得到 detail_url

使用requests.get

防止爬虫挂掉,一旦发现爬取的detail重复,就重新启动爬虫

根据detail_url获取网页html信息 => requests - > html

使用BeautifulSoup

若爬取太快,就等着解封

if html.status_code!=200

print('status_code if {}'.format(html.status_code))

根据html得到soup => soup

从soup中获取特定元素内容 => 岗位信息

保存数据到MongoDB中

# @author: limingxuan
# @contect: limx2011@hotmail.com
# @blog: https://www.jianshu.com/p/a5907362ba72
# @time: 2018-07-21
import requests
from bs4 import BeautifulSoup
import time
from pymongo import MongoClient
headers = {
'accept': "application/json, text/javascript, */*; q=0.01",
'accept-encoding': "gzip, deflate, br",
'accept-language': "zh-CN,zh;q=0.9,en;q=0.8",
'content-type': "application/x-www-form-urlencoded; charset=UTF-8",
'cookie': "JSESSIONID=""; __c=1530137184; sid=sem_pz_bdpc_dasou_title; __g=sem_pz_bdpc_dasou_title; __l=r=https%3A%2F%2Fwww.zhipin.com%2Fgongsi%2F5189f3fadb73e42f1HN40t8~.html&l=%2Fwww.zhipin.com%2Fgongsir%2F5189f3fadb73e42f1HN40t8~.html%3Fka%3Dcompany-jobs&g=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1531150234,1531231870,1531573701,1531741316; lastCity=101010100; toUrl=https%3A%2F%2Fwww.zhipin.com%2Fjob_detail%2F%3Fquery%3Dpython%26scity%3D101010100; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1531743361; __a=26651524.1530136298.1530136298.1530137184.286.2.285.199",
'origin': "https://www.zhipin.com",
'referer': "https://www.zhipin.com/job_detail/?query=python&scity=101010100",
'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
}
conn = MongoClient('127.0.0.1',27017)
db = conn.zhipin_jobs
def init():
items = db.Python_jobs.find().sort('pid')
for item in items:
if 'detial' in item.keys(): #当爬虫挂掉时,跳过已爬取的页
continue
detail_url = 'https://www.zhipin.com/job_detail/{}.html'.format(item['pid']) #单引号和双引号相同,str.format()新格式化方式
#第一阶段顺利打印出岗位页面的url
print(detail_url)
#返回的html是 Response 类的结果
html = requests.get(detail_url,headers = headers)
if html.status_code != 200:
print('status_code is {}'.format(html.status_code))
break
#返回值soup表示一个文档的全部内容(html.praser是html解析器)
soup = BeautifulSoup(html.text,'html.parser')
job = soup.select('.job-sec .text')
print(job)
#???
if len(job)<1:
continue
item['detail'] = job[0].text.strip() #职位描述
location = soup.select(".job-sec .job-location .location-address")
item['location'] = location[0].text.strip() #工作地点
item['updated_at'] = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()) #实时爬取时间
#print(item['detail'])
#print(item['location'])
#print(item['updated_at'])
res = save(item) #调用保存数据结构
print(res)
time.sleep(40)#爬太快IP被封了24小时==
#保存数据到MongoDB中
def save(item):
return db.Python_jobs.update_one({'_id':item['_id']},{'$set':item}) #why item ???
# 保存数据到MongoDB
if __name__ == '__main__':
init()

2018-07-23最新补充

由于之前设置睡眠4秒,爬取详情页才爬了30多个,就被封了IP 24小时。

暂时调整成了40秒,明天继续爬

后续再次实践的时候可以考虑参考使用代理IP池爬虫的方法

https://github.com/hjlarry/bosszhipin

最终结果就是在MongoBooster中看到新增了detail和location的数据内容

爬取岗位详情成功~

03 清洗数据

将salary拆分成low,high,avg

将发布时间统一成2018-07-xx格式

将工作经验统一成直聘格式,并且设置对应的level等级

以上完全按照原链接中的方法完成的,代码如下:

# @author: limingxuan
# @contect: limx2011@hotmail.com
# @blog: https://www.jianshu.com/p/a5907362ba72
# @time: 2018-07-23
# coding: utf-8
# In[83]:
import datetime
from pymongo import MongoClient
# In[84]:
conn = MongoClient('127.0.0.1',27017)
db = conn.zhipin_jobs
print(conn)
# In[85]:
def update(item):
return db.Python_jobs.update_one({"_id": item['_id']}, {"$set": item})
#时间统一格式
def clear_time():
items = db.Python_jobs.find({})
for item in items:
if not item['time'].find("布于"):
continue
item['time'] = item['time'].replace("发布于","2017-")
item['time'] = item['time'].replace("月","-")
item['time'] = item['time'].replace("日","")
if item['time'].find("昨天") > 0:
item['time'] = str(datetime.date.today() - datetime.timedelta(days = 1))
elif item['time'].find(":") > 0:
item['time'] = str(datetime.date.today())
update(item)
print(ok)
#print(item['time'])
#薪资统一格式,计算平均值
def clear_salary():
items = db.Python_jobs.find({})
for item in items:
if type(item['salary']) == type({}):
continue
salary_list = item['salary'].lower().replace('k','000').split("-")
if len(salary_list) != 2:
print(salary_list)
continue
try:
salary_list = [int(x) for x in salary_list]
except:
print(salary_list)
continue
item['salary'] = {
'low':salary_list[0],
'high':salary_list[1],
'avg':(salary_list[0] + salary_list[1])/2
}
update(item)
print('ok')
# 设置招聘的水平,分两次执行
def set_level():
items = db.Python_jobs.find({})
for item in items:
if item['experience'] == '应届生':
item['level'] = 1
elif item['experience'] == '1年以内':
item['level'] = 2
elif item['experience'] == '1-3年':
item['level'] = 3
elif item['experience'] == '3-5年':
item['level'] = 4
elif item['experience'] == '5-10年':
item['level'] = 5
elif item['experience'] == '10年以上':
item['level'] = 6
elif item['experience'] == '不限':
item['level'] = 10
update(item)
print('ok')
if __name__ == '__main__':
clear_time()
clear_salary()
set_level()

暂时还没办法将岗位detail拆分成岗位职责和任职要求(原作者没做,我就先略过)

预告


https://www.xamrdz.com/lan/53k1962561.html

相关文章: