通过各种点击观察,发现58同城的URL构造挺特殊的。
根据互联网协议和规则,一般查询参数都直接在cgi后加参数,如cgi?key=abc&page=1
这样的。
但是58喜欢赶潮,除了关键词key
之外,一些重要的查询参数(职业、行业、页码等)都在URL的目录中构造,而不是作为参数。这个技术我不太懂-_-!,大概是服务器对URL进行分析再获取参数吧,这个不重要。
(注:我是用python开发,刚入门,目前正在用BeautifulSoup扩展,所以经常提到一些相关术语。另外,定位方法我建议采用CSS选择器,语法是通用的。)
招聘搜索页源码分析
下面是我将几乎全部搜索条件都加上的全链接:
*http://bj.58.com/haidian/tech/pve_5363_244_pve_5754_1476_pve_5356_6_pve_5357_6/?key=%E6%95%B0%E6%8D%AE&minxinzi=3000_4999&postdate=20151209_20151216¶m6693=8&PGTID=0d303655-0047-792b-50b1-e40ba04c7e85&ClickID=1 *
好的,根据这个链接,以及各种尝试出来的判断,URL的结论如下:
- 第一部分:子域名。
bj.58.com
,其中bj
作为城市范围的“参数值”。值得一提的是,58同城没有省级分区,全都是针对某个城市。 - 第二部分:目录参数。以下按目录固定顺序排列:
-
/haidian/
即海淀区,代表了地区或地点“参数值”,还可以是/wudaokou/
五道口、/beijingdaxue/
北京大学等,还可以是/beijingzhoubian/
北京周边,都是区域那一栏所有选项的中文全拼。如果是现实全北京的数据的话,这个目录参数是被省略的的。 -
/tech/
即职位类别为"计算机/互联网"类。这一部分有点意思,如果改成/job/
就会不限分类,显示所有结果;如果改成/chengxuyuan/
则会显示"程序员"的子职业分类。也就是说,58不区分各种职业的层级关系,也不考虑多选——要么全选要么单选。 -
pve_5363_244_pve_5754_1476_pve_5356_6_pve_5357_6
这个是看起来最复杂的,但是稍微留意下也好理解,其实是——“更多”栏的筛选项,一般有四种参数在这里显示,每种之间用下划线连接,如果没有选择的话这里就不显示其值。其中pve_$$$$_??
是固定格式,$$$$是4位数字代表参数名,后面的??
是1~4位是不固定的数字代表参数值。- pve_5363:公司行业代号。后面的244是“计算机/互联网行业”。合在一起代表“公司行业为计算机及互联网行业”。
- pve_5754:公司性质代号。后面的1476代表“私营”企业。
- pve_5356:学历要求代号。后面的6代表“本科”。
- pve_5357:经验要求代号。后面的6代表“3年-5年”。
-
- 第三部分:查询参数。这里就没有固定顺序了。
- params6693:福利待遇。如果值是
1
,代表五险一金;6
代表周末双休。不可多选! - minixinzi:薪资范围。如
0_999
及3000_4999
等。
- params6693:福利待遇。如果值是
页码:
页码超出搜索结果的总页码时,会显示省略号。
但是结果再多,也只能显示到70页,和智联招聘差不多(到90页)。
包含招聘结果的大框架
页面唯一重要的列表信息,都包括在了这个框架中:
<div id="infolist" class="tablist cleft" tongji_id="ZP_job_list_div_items">
<dl logr="p_1_33416242837515_24319259084094_0_1_ses^composite^0" _pos="1" sortid="503338211" class="">一条招聘信息</dl>
</div>
框架定位关键是<div>
的id="infolist"
,而结果列表中每一条的定位关键为<dl>
标签包含logr
属性,且规律为logr="p_?_????_ses^composite??"
逐行结果的代码解析
每一条信息的源码如下(量比较大):
<dl logr='p_1_33416242837515_24319259084094_0_1_ses^composite^0' _pos="1" sortid='503338211'>
<dd class="w46">
<i infoid='24319259084094'></i>
<input type="hidden" uid='33416242837515_0_0' name="uid"/>
</dd>
<dt>
<a href='http://bj.58.com/chaoshishangye/24319259084094x.shtml' urlparams='psid=164836665190074319829635832&entinfo=24319259084094_0' target="_blank" class="t" _t='common'>数据处理员</a>
<span class="hoverinfobox" style="display: none;">
<div id="arrow">
<em></em>
<span></span>
</div>
<div id="tipsbox" class="tipsbox">
<div class="xboxcontent" class="tipsbox">
<div class="titbar"><h2>山东正元数字城市建设有限公司麻城项目</h2></div>
<ul class="zhanshi clearfix">
<li class="mar30">
<span>招聘职位:</span>全职招聘
</li>
<li>
<span>招聘人数:</span>若干 </li>
<li class="mar30">
<span>工作经验:</span>不限 </li>
<li>
<span>学历要求:</span>不限
</li>
<!--
<li class="mar30">
<span>工作地点:</span>北京
</li> -->
<li class="mar30">
<span>转正工资:</span>1000-2000元
</li>
</ul>
<p>
有积极的态度和人际关系,能吃苦耐劳,文化水平高中以上。
</p>
</div>
</div>
</span>
<span tag="bbbindcpc" url='http://bj.58.com/chaoshishangye/24319259084094x.shtml' name="zaixian_33416242837515"></span>
</dt>
<dd class="w271">
<a href='http://qy.58.com/33416242837515/' urlparams='psid=164836665190074319829635832&entinfo=24319259084094_0' target="_blank" class="fl" title="山东正元数字城市建设有限公司麻城项目">山东正元数字城市建设有限公司麻...</a>
</dd>
<dd class="w96"> 北京 </dd>
<dd class="w68"> 12-13 </dd>
</dl>
其中,一条信息的确认方式有3中:
-
dl [logr]
或dl [sortid]
或dl [_pos]
,合并定位 input [name="uid"]
-
div class="xboxcontent"
和div class="tipsbox"
合并定位
获取每条招聘信息的基本内容
- 企业ID:定位在
<i infoid='24319259084094'></i>
- uid:定位在
<input type="hidden" uid='33416242837515_0_0' name="uid"/>
- 职位名称及职位详情页URL:
<a href='http://bj.58.com/chaoshishangye/24319259084094x.shtml' urlparams='psid=164836665190074319829635832&entinfo=24319259084094_0' target="_blank" class="t" _t='common'>数据处理员</a>`
需要注意的是,详情url尽量结合href
和urlparams
参数一起构造,不过不放在一起也无所谓。
- 企业名称:定位在
<div class="titbar"><h2>山东正元数字城市建设有限公司麻城项目</h2></div>
- 招聘职位:查找语法是->
ul[class*=zhanshi] li nth-of-type(1)
或者不用nth-of-type()
语法,而是按文本匹配。 - 招聘人数:查找语法是->
ul[class*=zhanshi] li nth-of-type(2)
或者不用nth-of-type()
语法,而是按文本匹配。 - 工作经验:查找语法是->
ul[class*=zhanshi] li nth-of-type(3)
或者不用nth-of-type()
语法,而是按文本匹配。 - 学历要求:查找语法是->
ul[class*=zhanshi] li nth-of-type(4)
或者不用nth-of-type()
语法,而是按文本匹配。 - 转正工资:查找语法是->
ul[class*=zhanshi] li nth-of-type(5)
或者不用nth-of-type()
语法,而是按文本匹配。 - 职位描述:查找语法是->
ul[class*=zhanshi] + p
- 企业名称及链接:定位在以下代码中。注意企业名称才用
title
属性中的,而不是被阉割的文本处。
<dd class="w271"> <a href='http://qy.58.com/33416242837515/' urlparams='psid=164836665190074319829635832&entinfo=24319259084094_0' target="_blank" class="fl" title="xxxx有限公司xx项目">xxxx有限公司...</a></dd>`
- 工作地点:
<dd class="w96"> 北京 </dd>
- 发布日期:
<dd class="w68"> 12-13 </dd>
判断是否为推广信息
如果一行信息内包括这条,那么就是推广信息:
<a class="tuiguang" title="58同城建议您优选选择精准推广" rel="nofollow" target="_blank" href="http://e.58.com/zhaopin/jingzhun.html#go">精准</a>
通过<a>
标签的class="tuiguang"
来定位。
如果是正常消息,则没有这个链接,且只显示文本的“今天”或者是“12-12”这种具体日期。
获取当前页码及下一页链接
这一步其实是非常重要的!直接关系到是否抓瞎。
首先,58的设置是这样的:
58最多只显示70页信息,每页45条。强行打开70页以上的页面,或者超过当前结果的总页数,都会显示新信息较少,我们为您推荐以下相关信息:
。
我们先来看源码,然后再处理。
<div class="pagerout">
<div class="pager" tongji_id="ZP_job_list_div_next">
<a class="prv" href="/job/pn7/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>上一页</span ></a>
<a href="/job/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>1</span></a>
<a href="/job/pn2/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>2</span></a>
<a href="/job/pn3/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>3</span></a>
...
<a href="/job/pn4/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>4</span></a>
<a href="/job/pn5/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>5</span></a>
<a href="/job/pn6/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>6</span></a>
<a href="/job/pn7/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>7</span></a>
<strong><span>8</span></strong>
<a href="/job/pn9/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>9</span></a>
<a href="/job/pn10/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>10</span></a>
<a href="/job/pn11/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>11</span></a>
<a href="/job/pn12/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>12</span></a>
<a class="next" href="/job/pn9/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0">
<span>下一页</span></a>
<a href="/job/?key=%E6%95%B0%E6%8D%AE&cmcskey=%E6%95%B0%E6%8D%AE&final=1&specialtype=gls&canclequery=isbiz%3D0" class="recently">
<span>最新信息</span></a>
</div>
</div>
从上面我们可以这样得到些信息:
- 上一页链接:
div[class="pagerout"] a[class="prv"]
,获取其href
属性值就好了。如果没有,表示正在第一页。
- 下一页链接:
div[class="pagerout"] a[class="next"]
,获取其href
属性值就好了。如果没有,表示正在最后一页。 - 当前页码:
div[class="pagerout"] div[class="pager"] strong
,当前页是不带链接的,所以要这样获取。
判断搜索结果是否读完
通过测试发现,根据结果数量的不同,除了正常外汇产生以下结果:
- 显示
新信息较少,我们为您推荐以下相关信息:
一般是因为超过了应有的页码了。这样的信息通过源码找到<dt class="shortMsg">新信息较少,我们为您推荐以下相关信息:</dt>
就可以了。 - 显示
很抱歉,没有找到符合已选条件的信息。\n建议您:
,这是因为搜索条件太苛刻没有符合条件的。这样的,通过源码找到:
<i class="ico report"></i><p>很抱歉,没有找到符合已选条件的信息。<br />建议您:</p>
招聘详细页源码分析
这个页面比较简单,除了企业联系方式是动态加载的图片外都比较好定位抓取。不过联系方式也对我没什么太大用就不费那功夫了。
精简招聘信息
是被包含在头文件中用来给搜索引擎搜索用的,所以是精华中的精华哈哈。如下:
<meta name="description" content="[最新招聘信息]诚聘诚聘数据分析师5000+1人,工作地点位于北京海淀中关村,公司规模100-499人,薪资待遇5000-8000元,工作经验1-2年,学历要求大专,招聘岗位职责: 建立公司数据分析的系统,组织数据分析报表的整合和规范、优化; 建立公司数据管理、查询的各项规章制度; 建立公司每日、周、月、季、年度数据分析报表模板; 研究数据分析的方法,做到报表制作, 100)" />
只要通过<meta name="description"
定位,获取其content
属性值`就好了。
获取招聘基本信息
所有的信息都包含在了<div class="wb-main">...</div>
框架中。能够找到的信息如下:
- 职位名称:
- 更新时间:
- 浏览人数和投递人数:这个略过,没什么用。
- 企业名称及链接:都在
<a class="companyName" >
,直接获取href
就行了。 - 营业执照是否已经过验证:
<div class="vip-yan fl"><span title="营业执照已验证" class="licIcon"></span>营业执照已认证</div>
。找到<div class="vip-yan fl">
就好了。 - 所在行业、企业性质、企业规模和登记时间都在这里了:
<div class="compMsg clearfix">
<ul>
<li>
<span>行业:</span>
<a href="http://qy.58.com/bj_264/" target="_blank" >广告/创意</a>
</li>
<li>
<span>性质: </span>私营
</li>
<li class="scale">
<span>规模: </span>100-499人
</li>
<li class="joinday" style="display: none;">
<span>入驻时长:</span>174天
</li>
</ul>
</div>
写累了,直接上BeautifulSoup格式的css选择器的查找语法,分别为:
所在行业 =div[class*=compMsg] ul li a[href]
找到,
企业性质 = div[class*=compMsg] ul li nth-of-type(2)
,
企业规模 = div[class*=compMsg] ul li nth-of-type(3)
或者li[class="scale"]
,
入驻时间 = div[class*=compMsg] ul li nth-of-type(4)
或li[class="joinday"]
。
获取联系信息
都包含在这个div中:
<div class="contact mt25" id="lianxi" tongji_id="ZP_job_detail_div_contact">...</div>
然后可以找到这些信息:
- 联系人:
<span class="conTip">王经理 <span>(联系我时请说明是在58同城上看到的)</span></span>
,定位方法:div[class="conTip"]
。
- 工作地点:源码有点长,定位方法:只能用文字匹配了,找到
<dt>工作地址:</dt>
和<span class="area">
这2个标签,它们
中间的标签就是地址。 - 卫星定位:其实也不用费劲,直接找到
a[class="map"]
,获取其href
然后用增则表达式匹配2个116.337795
这种数字,就得到精确坐标了。源码如下:
<a class="map" href="javascript:setbg('诚聘数据分析师',430,240,'http://qy.58.com/mapdetail.html?lat=116.337795%2C39.977523&name=%E5%B7%A5%E4%BD%9C%E5%9C%B0%E7%82%B9');"><i></i>查看地图</a>
获取企业介绍
企业信息都包含在这里面:
<div class="compIntro" id="gongsi">...</div>
定位方式为:直接div[class="compIntro"]
或#gongsi
获取所有文字内容就是企业介绍了。
企业主页源码分析
58还真是方便,再牛的企业都是一模一样的简单网页。不过还好,这也方便获取数据了。
这个页面极其简单,但是有一点需要注意,数据是用表格动态呈现的,每种信息的位置并不固定,是根据企业有没有这个信息才显示出来的。所以在信息定位上,尽量避免用序号,只能用中文匹配了。。需要获取的数据如下:
- 卫星定位:在头文件中,如
<meta name="location" content="province=北京;city=北京; coord=116.404,39.915">
。找到<meta name="location" />
获取coord
属性值就好了。
- 企业名称及ID:
div[class="compT"] a[href]
就可以找到企业名称,在href
属性中的是/ID/
这样的格式,去掉/
就好了。 - 企业资质:最好在
div[class="basicMsg"] tr
中用文字匹配。 - 企业性质:最好在
div[class="basicMsg"] tr
中用文字匹配。 - 企业行业:最好在
div[class="basicMsg"] tr
中用文字匹配。 - 企业规模:最好在
div[class="basicMsg"] tr
中用文字匹配。 - 联系人: 最好在
div[class="basicMsg"] tr
中用文字匹配。 - 联系电话:用文字匹配或
[class="telNum"] img
,注意,联系电话都是图片格式的,而且可以不止一个!(省事的话就别下载图片了,保存链接就好了,因为图片来源明显不是静态图片而是服务器动态生成的。) - 企业网址(自己的):最好在
div[class="basicMsg"] tr a
中或用文字匹配。 - 企业邮箱:和电话一样,用文字匹配或
[class="telNum"] img
来找图片。 - 公司地址:最好在
div[class="basicMsg"] tr
中用文字匹配。
企业信用档案页面URL及源码分析
这个页面不知道入口在哪里?偶然看到的,然后心里大呼——哇塞!哈哈
虽然找不到入口或者查询页面,但是发现其实看懂URL就很简单了,必要格式如下:
http://credit.vip.58.com/usercredit?userId=企业ID
那么这时候刚才获取的企业ID就起作用了。手工输入了一下,ID对的话每家企业都能出来。
建立了档案的企业——会显示巨详细的信息!连法人代表、注册资本、详细地址全都有。
没建立档案的企业——也会显示页面,但信息处全都是空白。
下面就简单分析下基本信息的获取。
获取企业营业执照信息
表格基本上是固定位置的,因为大家营业执照都一样嘛哈哈~
首先获取信息框架:div[class="zzxx_ta"] table
,然后再到这个框架里操作,就简单多了。
下面是信息定位分析:
- 公司名称:
td[class="tdbg"] + td
的第1项或span[class="headTitle"]
- 注册号:
td[class="tdbg"] + td
的第2项 - 经营地址:
td[class="tdbg"] + td
的第3项 - 注册资本:
td[class="tdbg"] + td
的第4项 - 成立日期:
td[class="tdbg"] + td
的第5项 - 法定代表人:
td[class="tdbg"] + td
第6项 - 登记机关:
td[class="tdbg"] + td
的第7项 - 企业类型:
td[class="tdbg"] + td
的第8项 - 营业期限:
td[class="tdbg"] + td
的第9项 - 核准日期:
td[class="tdbg"] + td
的第10项 - 登记状态:
td[class="tdbg"] + td
的第11项 - 在营(开业)企业:
td[class="tdbg"] + td
的第12项 - 经营范围:
td[class="tdbg"] + td
的第13项
获取企业其他信息
- 企业简介:
div[class="briefIntro"]
- 企业图片:
div[class="albumBox"] img
- 企业抽查检查信息:
div[class="zzxx_ta"] nth-of-type(1) tr
,如果有记录则显示,无记录则只显示一条“无xx信息”。可以适当排除。 - 企业经营异常信息:
div[class="zzxx_ta"] nth-of-type(2) tr
,如果有记录则显示,无记录则只显示一条“无xx信息”。可以适当排除。 - 企业行政处罚信息:
div[class="zzxx_ta"] nth-of-type(3) tr
,如果有记录则显示,无记录则只显示一条“无xx信息”。可以适当排除。 - 企业严重违法信息:
div[class="zzxx_ta"] nth-of-type(4) tr
,如果有记录则显示,无记录则只显示一条“无xx信息”。可以适当排除。