avatar

目录
狗贼女朋友毕设(1)


先看要求

wrp

选择一个人才招聘网, 查询条件,爬取数据,图表形式展现,Python,大数据技术。

那先打开网站。番禺招才网,我已经选择好了查询条件就是Web开发。

Code
1
http://panyu.goodjob.cn/SearchResult.aspx?jobFunction=330&jobLocation=2&postDate=30&calling=&keyWordType=0&keyWord=&MemjobLocation=&searchType=quickSearch&reqOrderBy=1

wrp

由于这个网站翻页用了Js来加载,所以不能爬取翻页,只能单页爬取,所以爬一页也够应付了把。

干正事

分析网站

先观察网站结构,意思就是你要爬什么比较方便,通常都是 薪资、公司名称、福利待遇、工作地点

工作地点:就不用看了,番禺招才网,不可能出现北上深等地点了。

福利待遇:做图表插入这些比较麻烦,不方便划水。

那就看薪资和公司名称。

第一步

F12 打开开发者工具。

通常打开就是这样子,不过这样子不方便分析,设置一下。

wrp

先点一下这三点,接着点击框柱的那个东西。

wrp

然后他就会单独变成一个浏览器窗口了。这样子看得就舒服很多了.

wrp

第二步

点击一下这个鼠标

wrp

然后把鼠标移到公司那里,并点击一下,下面那个开发者浏览器就会移动到相关的代码处.

wrp

观察他附近的代码

Code
1
2
3
4
5
<td width="26%" class="h06">                                                  
<a href="/job/com320997.html" target="_blank"class="link01" title="广州市铂桥信息科技有限公司">
广州市铂桥信息科技有限公...
</a>
</td>

wrp

代码分析

代码已经是写好的了。

  • 装好Python3
  • 在安装库,装好的可以跳过
  • 打开cmd
  • 分别输入以下代码
Code
1
2
3
pip install requests
pip install re
pip install pyecharts-0.1.9.4-py2.py3-none-any.whl(这是个文件)

打开Pycharm,没有就打开Nopte++

这是头部:

Code
1
2
3
4
5
# -*- coding: utf-8 -*-
import re
import requests
from requests.exceptions import RequestException
from pyecharts import Bar

导入库的意思,和写java一样。

这是一个判断网页状态的函数:

headers 是我写的一个全局变量,用作伪造百度爬虫协议。反正和老师讲的时候就说伪造百度爬虫协议。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#伪造百度爬虫协议
headers = {
'User-Agent': 'Mozilla/5.0 (compatible, Baiduspider/2.0;http://www.baidu.com/search/spider.html)'
}
#获取网页状态,200返回文本
def get_page_status(url):
try:
respone = requests.get(url, headers=headers)
respone.encoding = 'utf-8'
if respone.status_code == 200:
return respone.text
return None
except RequestException:
return None

中间部分:

Code
1
def get_main(soup): 定义函数
Code
1
2
#这是一个正则变量,原本是三个正则变量,我把他堆在了一起。
item = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">.*?<td width="9%" class="h06" style="color:Red">(.*?)</td>.*?<div class="fulidaiyu".*?><span>(.*?)</div>',soup,re.S)

原来三个正则变量长这样

Code
1
2
3
title = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">',soup,re.S)
money = re.findall('<td width="9%" class="h06" style="color:Red">(.*?)</td>',soup,re.S)
fuli = re.findall('<div class="fulidaiyu".*?><span>(.*?)</div>',soup,re.S)
Code
1
2
re.findall  这个函数什么意思,字面意思,find 查找,all所有。findall 查找所有
title = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">',soup,re.S)

往上拉,看刚才分析网页那里,我用方框框柱的,我们要获取他title值里的公司名字。所以要定位,那么定位需要什么,需要一个明确的特征。

举个栗子:

有人来参加你毕业典礼,坐公交来,怎么来了。你就要告诉他,你要到市桥,搭番67,是开往宝墨园方向的车,到龙湾路口下车。

那么我们要获取title的值,怎么说了:首先你要来 “(td width=”26%” class=”h06”>”这里,然后找到“(a>”这个标签,然后往前走,到title这里停下,把他的名字拿出来。

wrp

补充下知识:

正则 待匹配字符 匹配 结果 说明
李.? 李杰和李莲英和李二棍子 李杰 李莲 李二 ?表示重复零次或一次,即只匹配"李"后面一个任意字符
李.* 李杰和李莲英和李二棍子 李杰和李莲英和李二棍子 *表示重复零次或多次,即匹配"李"后面0或多个任意字符
李.+ 李杰和李莲英和李二棍子 李杰和李莲英和李二棍子 +表示重复一次或多次,即只匹配"李"后面1个或多个任意字符
李.{1,2} 李杰和李莲英和李二棍子 李杰和 李莲英 李二棍 {1,2}匹配1到2次任意字符

注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配

正则待匹配字符匹配

正则 待匹配字符 匹配结果 说明
李.*? 李杰和李莲英和李二棍子 李李李 惰性匹配

. * ? 的用法

Code
1
2
3
4
5
6
7
. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x

就是取前面任意长度的字符,直到一个x出现

回来看这里,第一步我们让他走到 td那里,然后.*?是为什么了,因为他有一个换行,我们需要这么写来匹配他的换行,当然其他也可以不过我不知道,我写法就是这样。

接着进入<a 标签, 中间有href 就是超链接这些,全部忽略,也就是自己用 .*?这个写法来跳过,到了title这里双引号带上,加上一个括号(.*?),为什么要加括号,因为你得让程序知道。你要匹配的内容就是这里的值。

Code
1
title = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">',soup,re.S)

wrp

这是输出信息:

wrp

下一句的money,fuli 也是这样。这样子直接输出格式很丑。

Code
1
2
3
title = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">',soup,re.S)
money = re.findall('<td width="9%" class="h06" style="color:Red">(.*?)</td>',soup,re.S)
fuli = re.findall('<div class="fulidaiyu".*?><span>(.*?)</div>',soup,re.S)

输出结果:

wrp

合并为一条,你可以观察上面三条的代码。中间加上的.*?是为了忽略其他代码。直接定位到准确的属性,最后面re.S 是匹配换行,默认写法,不需要知道为啥。这些也是我百度回来的。

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
Code
1
item = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">.*?<td width="9%" class="h06" style="color:Red">(.*?)</td>.*?<div class="fulidaiyu".*?><span>(.*?)</div>',soup,re.S)
Code
1
2
3
4
job={}    	  #用来存放数据的元组 
names = [] #用来存放数据的数组
moneys = [] #用来存放数据的数组
fulis = [] #用来存放数据的数组

For循环

先学习下Python 的 For 循环:

for循环的语法格式如下:

Code
1
2
for iterating_var in sequence:
statements(s)

看不懂了吧,我也看不懂,直接看例子把。

Code
1
2
3
4
5
6
# -*- coding: UTF-8 -*-
fruits = ['banana', 'apple', 'mango']
for index in range(len(fruits)):
print '当前水果 :', fruits[index]

print "Good bye!"

输出结果:

Code
1
2
3
4
当前水果 : banana
当前水果 : apple
当前水果 : mango
Good bye!

其实就是

在for循环里

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
for 要输出的东西 in 要拿来循环的东西:

看下C语言的:
for (int i=0;i<100;i++)
{
printf("%d",i++);
}
用Python写:
for i in range(1,100):
print(i)
你看,都是输出i range是什么意思,range(start, stop)
start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5

回来看代码:

我分别把item 和items 都输出一次,看下差异

Code
1
2
3
#使用for循环,将item 那个正则爬取下来的数据由数组类型转为元组类型。
for items in item:
printf(items)

items输出结果:

每一个输出结果前面都是括号

wrp

Code
1
2
3
#使用for循环,将item 那个正则爬取下来的数据由数组类型转为元组类型。
for items in item:
printf(item)

输出item:

输出结果前多了个[]号,并且很乱。

wrp

括号和方括号有什么差别了

在Python中 () 代表元组类型 [] 代表列表类型。

为什么我要多此一举转换他的格式了。看上面item 输出的结果。就是列表的输出结果,数据很乱,并且有很多不应该出现的东西,比如\n、<span </span 空格这些,你数据要整洁性,你就得把它去除,但是列表不能实现,但是转换为元组就可以了。

元组有replace,strip函数等可以使用

Code
1
2
3
4
5
6
7
replace(old, new)
old -- 将被替换的子字符串。
new -- 新字符串,用于替换old子字符串。

strip([chars])
chars -- 移除字符串头尾指定的字符序列。
chars 通常可以不写,就是默认为空格。

学习元组:

Code
1
2
3
4
5
6
7
访问元组

tup1 = ('physics', 'chemistry', 1997, 2000)
tup2 = (1, 2, 3, 4, 5, 6, 7 )

print "tup1[0]: ", tup1[0]
print "tup2[1:5]: ", tup2[1:5]

输出结果:

Code
1
2
tup1[0]:  physics
tup2[1:5]: (2, 3, 4, 5)

元组访问从[0]开始,就和数组一样。元组访问从[0]开始,就和数组一样。

Code
1
2
3
4
5
    item = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">.*?<td width="9%" class="h06" style="color:Red">(.*?)</td>.*?<div class="fulidaiyu".*?><span>(.*?)</div>',soup,re.S)
for items in item:
job['name'] = items[0].replace("有限公司","")
job['money'] = items[1].replace("以上", "").strip().replace("面议","0")
job['fuli'] = items[2].replace('<span>', '').replace('</span>', '')

items[0]是什么数据了,就是item 那串合并的正则语法里,第一个括号内的值,就是公司的名称。

items[1]就是薪资、items[2]就是福利待遇了。

items[0]输出结果:

wrp

学习下Dict,字典类型,按照java中就是Json类型:

Code
1
2
字典原型:
dict = {key1 : value1, key2 : value2 }
Code
1
2
3
4
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}

print "dict['Name']: ", dict['Name']
print "dict['Age']: ", dict['Age']

输出结果:

Code
1
2
dict['Name']:  Zara
dict['Age']: 7

那么回来代码这里

job[‘name’] 这里的name 就相当于 {key:value} 中的key

value 就是 = 号后面的items[0].replace(“有限公司”,””)内容

Code
1
2
3
job['name'] = items[0].replace("有限公司","")
job['money'] = items[1].replace("以上", "").strip().replace("面议","0")
job['fuli'] = items[2].replace('<span>', '').replace('</span>', '')

这几个是什么东西了,names、moneys、fulis 都是list类型,为什么又要多此一举,因为后面画柱形图时,他只接受list类型的数据(可能元组类型的也可以,不过没试过。),append 就是添加。

Code
1
2
3
names.append(job['name'])
moneys.append(job['money'])
fulis.append(job['fuli'])

画柱形图:

首先定义,Bar(“我的第一个图表”, “这里是副标题”)后面的width 设置图表宽度这些值

add(“随便写,可以空”,X轴数据,Y轴数据,mark_point=[“average”]求平均值,is_convert=True X Y轴转换)

后面的 mark_point=[“average”]求平均值,is_convert=True X Y轴转换 这两个东西,正常都不用加,只需要加前面三个就可以了。最重要的就是X Y轴数据

render()是生成一个render.html 的文件。提供来给你看图表的。你可以自定义名字

bar.render(“abc.html”) 就是会生成一个叫abc.html 的文件。默认叫render.html

Code
1
2
3
bar = Bar("番禺招聘网IT行业薪资柱形图",width=1200)
bar.add("Web",names,moneys,mark_point=["average"],is_convert=True)
bar.render()

中间部分完整代码

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def get_main(soup):
#使用正则爬取
item = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">.*?<td width="9%" class="h06" style="color:Red">(.*?)</td>.*?<div class="fulidaiyu".*?><span>(.*?)</div>',soup,re.S)
job={}
names = []
moneys = []
fulis = []
for items in item:
job['name'] = items[0].replace("有限公司","")
job['money'] = items[1].replace("以上", "").strip().replace("面议","0")
job['fuli'] = items[2].replace('<span>', '').replace('</span>', '')
names.append(job['name'])
moneys.append(job['money'])
fulis.append(job['fuli'])
#画柱形
bar = Bar("番禺招聘网IT行业薪资柱形图",width=1200)
bar.add("",names,moneys,mark_point=["average"],is_convert=True)
bar.render()

main函数调用:

Code
1
2
3
4
5
6
7
def main():
url = 'http://panyu.goodjob.cn/SearchResult.aspx?jobFunction=330&jobLocation=2&postDate=30&calling=&keyWordType=0&keyWord=&MemjobLocation=&searchType=quickSearch&reqOrderBy=1'
html = get_page_status(url)
get_main(html)

if __name__ == '__main__':
main()

正常的函数调用传值

最后一段 if name == ‘main 类似于Java的这个main函数,就是告诉程序这里是程序的入口。

Code
1
2
3
4
5
6
7
8
9
public class HelloWorld {

public static void main(String[] args) {

System.out.println("HelloWorld");

}

}

不过Python是一种解释型脚本语言,其实加不加都可以,但是为了代码规范化就加了,差不多就是这样,如果老师问了就这么回答,如果问得还深一点就说不会吧。这个东西解释起来太麻烦了。

最后效果图:

wrp

六级快结束了,到时间接程某了,再见。

文章作者: KeyboArd
文章链接: https://www.wrpzkb.cn/GouZeiNpy/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 KeyboArd's Blog
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论