先看要求
选择一个人才招聘网, 查询条件,爬取数据,图表形式展现,Python,大数据技术。
那先打开网站。番禺招才网,我已经选择好了查询条件就是Web开发。
1 | http://panyu.goodjob.cn/SearchResult.aspx?jobFunction=330&jobLocation=2&postDate=30&calling=&keyWordType=0&keyWord=&MemjobLocation=&searchType=quickSearch&reqOrderBy=1 |
由于这个网站翻页用了Js来加载,所以不能爬取翻页,只能单页爬取,所以爬一页也够应付了把。
干正事
分析网站
先观察网站结构,意思就是你要爬什么比较方便,通常都是 薪资、公司名称、福利待遇、工作地点
工作地点:就不用看了,番禺招才网,不可能出现北上深等地点了。
福利待遇:做图表插入这些比较麻烦,不方便划水。
那就看薪资和公司名称。
第一步
按F12 打开开发者工具。
通常打开就是这样子,不过这样子不方便分析,设置一下。
先点一下这三点,接着点击框柱的那个东西。
然后他就会单独变成一个浏览器窗口了。这样子看得就舒服很多了.
第二步
点击一下这个鼠标
然后把鼠标移到公司那里,并点击一下,下面那个开发者浏览器就会移动到相关的代码处.
观察他附近的代码
1 | <td width="26%" class="h06"> |
代码分析
代码已经是写好的了。
- 装好Python3
- 在安装库,装好的可以跳过
- 打开cmd
- 分别输入以下代码
1 | pip install requests |
打开Pycharm,没有就打开Nopte++
这是头部:
1 | # -*- coding: utf-8 -*- |
导入库的意思,和写java一样。
这是一个判断网页状态的函数:
headers 是我写的一个全局变量,用作伪造百度爬虫协议。反正和老师讲的时候就说伪造百度爬虫协议。
1 | #伪造百度爬虫协议 |
中间部分:
1 | def get_main(soup): 定义函数 |
1 | #这是一个正则变量,原本是三个正则变量,我把他堆在了一起。 |
原来三个正则变量长这样
1 | title = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">',soup,re.S) |
1 | re.findall 这个函数什么意思,字面意思,find 查找,all所有。findall 查找所有 |
往上拉,看刚才分析网页那里,我用方框框柱的,我们要获取他title值里的公司名字。所以要定位,那么定位需要什么,需要一个明确的特征。
举个栗子:
有人来参加你毕业典礼,坐公交来,怎么来了。你就要告诉他,你要到市桥,搭番67,是开往宝墨园方向的车,到龙湾路口下车。
那么我们要获取title的值,怎么说了:首先你要来 “(td width=”26%” class=”h06”>”这里,然后找到“(a>”这个标签,然后往前走,到title这里停下,把他的名字拿出来。
补充下知识:
正则 | 待匹配字符 | 匹配 结果 | 说明 |
---|---|---|---|
李.? | 李杰和李莲英和李二棍子 | 李杰 李莲 李二 | ?表示重复零次或一次,即只匹配"李"后面一个任意字符 |
李.* | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 | *表示重复零次或多次,即匹配"李"后面0或多个任意字符 |
李.+ | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 | +表示重复一次或多次,即只匹配"李"后面1个或多个任意字符 |
李.{1,2} | 李杰和李莲英和李二棍子 | 李杰和 李莲英 李二棍 | {1,2}匹配1到2次任意字符 |
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
正则待匹配字符匹配
正则 | 待匹配字符 | 匹配结果 | 说明 |
---|---|---|---|
李.*? | 李杰和李莲英和李二棍子 | 李李李 | 惰性匹配 |
. * ? 的用法
1 | . 是任意字符 |
回来看这里,第一步我们让他走到 td那里,然后.*?是为什么了,因为他有一个换行,我们需要这么写来匹配他的换行,当然其他也可以不过我不知道,我写法就是这样。
接着进入<a 标签, 中间有href 就是超链接这些,全部忽略,也就是自己用 .*?这个写法来跳过,到了title这里双引号带上,加上一个括号(.*?),为什么要加括号,因为你得让程序知道。你要匹配的内容就是这里的值。
1 | title = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">',soup,re.S) |
这是输出信息:
下一句的money,fuli 也是这样。这样子直接输出格式很丑。
1 | title = re.findall('<td width="26%" class="h06">.*?<a.*?title="(.*?)">',soup,re.S) |
输出结果:
合并为一条,你可以观察上面三条的代码。中间加上的.*?是为了忽略其他代码。直接定位到准确的属性,最后面re.S 是匹配换行,默认写法,不需要知道为啥。这些也是我百度回来的。
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
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) |
1 | job={} #用来存放数据的元组 |
For循环
先学习下Python 的 For 循环:
for循环的语法格式如下:
1 | for iterating_var in sequence: |
看不懂了吧,我也看不懂,直接看例子把。
1 | # -*- coding: UTF-8 -*- |
输出结果:
1 | 当前水果 : banana |
其实就是
在for循环里
1 | for 要输出的东西 in 要拿来循环的东西: |
回来看代码:
我分别把item 和items 都输出一次,看下差异
1 | #使用for循环,将item 那个正则爬取下来的数据由数组类型转为元组类型。 |
items输出结果:
每一个输出结果前面都是括号
1 | #使用for循环,将item 那个正则爬取下来的数据由数组类型转为元组类型。 |
输出item:
输出结果前多了个[]号,并且很乱。
括号和方括号有什么差别了
在Python中 () 代表元组类型 [] 代表列表类型。
为什么我要多此一举转换他的格式了。看上面item 输出的结果。就是列表的输出结果,数据很乱,并且有很多不应该出现的东西,比如\n、<span </span 空格这些,你数据要整洁性,你就得把它去除,但是列表不能实现,但是转换为元组就可以了。
元组有replace,strip函数等可以使用
1 | replace(old, new) |
学习元组:
1 | 访问元组 |
输出结果:
1 | tup1[0]: physics |
元组访问从[0]开始,就和数组一样。元组访问从[0]开始,就和数组一样。
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) |
items[0]是什么数据了,就是item 那串合并的正则语法里,第一个括号内的值,就是公司的名称。
items[1]就是薪资、items[2]就是福利待遇了。
items[0]输出结果:
学习下Dict,字典类型,按照java中就是Json类型:
1 | 字典原型: |
1 | dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} |
输出结果:
1 | dict['Name']: Zara |
那么回来代码这里
job[‘name’] 这里的name 就相当于 {key:value} 中的key
value 就是 = 号后面的items[0].replace(“有限公司”,””)内容
1 | job['name'] = items[0].replace("有限公司","") |
这几个是什么东西了,names、moneys、fulis 都是list类型,为什么又要多此一举,因为后面画柱形图时,他只接受list类型的数据(可能元组类型的也可以,不过没试过。),append 就是添加。
1 | names.append(job['name']) |
画柱形图:
首先定义,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
1 | bar = Bar("番禺招聘网IT行业薪资柱形图",width=1200) |
中间部分完整代码
1 | def get_main(soup): |
main函数调用:
1 | def main(): |
正常的函数调用传值
最后一段 if name == ‘main 类似于Java的这个main函数,就是告诉程序这里是程序的入口。
1 | public class HelloWorld { |
不过Python是一种解释型脚本语言,其实加不加都可以,但是为了代码规范化就加了,差不多就是这样,如果老师问了就这么回答,如果问得还深一点就说不会吧。这个东西解释起来太麻烦了。
最后效果图:
六级快结束了,到时间接程某了,再见。