爬虫入门之牛客网官方实习网页练习~~~~
urllib库
urllib提供的功能就是利用程序去执行各种HTTP请求。如果要模拟浏览器完成特定功能,需要把请求伪装成浏览器。伪装的方法是先监控浏览器发出的请求,再根据浏览器的请求头来伪装,User-Agent头就是用来标识浏览器的。
urllib是Python标准库的一部分,包含urllib.request,urllib.error,urllib.parse,urllib.robotparser四个子模块,这里主要介绍urllib.request的一些简单用法。
urllib.request
urllib.request.urlopen
urlopen()方法可以实现最基本请求的发起
urlopen(url,data,timeout)
url即为URL;
data是访问URL时要传送的数据;
timeout时设置超时时间;
第二、三参数是可以不传送的,data默认为空None,timeout默认为sock._GLOBAL_DEFAULT_TIMEOUT;
执行Urlopen方法之后,返回一个response对象,返回信息便保存在这里。
response对象有一个read()方法,可以返回获取到的网页内容。
urllib.request.Resquest
用Request类构建了一个完整的请求,增加了headers等一些信息.
首先,导入request模块1
2import urllib.request
from urllib.request import urlopen
具体程序如下:1
2
3
4
5
6
7headers = {'User-Agent' : 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:29.0)Gecko/20100101 Firefox/29.0'}
req = urllib.request.Request(url=url,headers=headers)
try:
res = urllib.request.urlopen(req)
except urllib.error.URLError as e:
return e
page_content = res.read()
BeautifulSoup库
BeautifulSoup是用来从HTML或XML中提取数据的Python库。
导入:1
from bs4 BeautifulSoup
BeautifulSoup的第一个入参是文档,第二个入参是文档解析器,默认情况下的优先顺序是:lxml,html5lib,python标准库。其中只有lxml支持xml文档的解析。1
2page_content=BeautifulSoup(page_content,"lxml")
return page_content
其中,read() 方法用于从文件读取指定的字节数,如果未给定或为负则读取所有。
经过BeautifulSoup处理后,打印出来的就是网页的前端代码,它将一些其他的信息滤除掉了。
BeautifulSoup中find和find_all的用法
BeautifulSoup中内置了一些查找方法,最常用的是find()和find_all函数;
find_all得到所有符合条件的结果(形式:列表list),find只返回第一个符合条件的结果,所以find()后面可以直接接.text或者get_text()来获取标签中的文本。
注:find_all和findAll这两个方法是完全相同的,在新代码中,应该使用小写版本find_all,但是老的名字仍然可用。
SSL证书
现在随处可见https开头的网站,urllib2可以为HTTPS请求验证SSL证书,就像web浏览器一样,如果网站的SSL证书是经过CA认证的,则能够正常访问,如:https://www.baidu.com/等...
如果没有CA认证的网站用urllib2访问的时候,会报出SSL(error)
所以,如果以后遇到这种网站,我们需要单独处理SSL证书,让程序忽略SSL证书验证错误,即可正常访问。
这时需要用到Python中的ssl模块。
1 | import ssl |
1.表示导入python ssl处理模块
2.表示忽略未经核实的SSL证书认证
HTML程序解析
通过BeautifulSoup处理后,我们得到了网页的HTML程序,下面要做的就是对HTML程序进行解析,提取出我们所需要的信息。
具体的解析方法,观察HTML代码寻找规律,对于牛客网实习官方信息而言,它的前端代码为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28<li class="clearfix">
<div class="reco-job-main">
<div class="reco-job-pic">
<img src="https://uploadfiles.nowcoder.com/images/20180522/303498_1526990692890_0D6BF0A200B09382C4C32821CB2EDA28">
</div>
<div class="reco-job-cont">
<a href="/job/639?jobIds=2601" class="reco-job-title" target="_blank">软件开发工程师</a>
<div class="reco-job-com">
上海孝庸资产管理有限公司
</div>
</div>
<div class="reco-job-info">
<div class="">
<span class="nk-txt-ellipsis js-nc-title-tips job-address" data-title="上海"><i class="icon-map-marker"></i>上海</span>
<span><span class="ico-nb">¥</span>面议/天</span>
<span class="job-status-tag job-status-tag1">处理快</span>
</div>
<div class="reco-job-detail">
<span class="publisher-name js-nc-title-tips" title="上海孝庸资产管理有限公司">上海孝庸资产管理有限公司</span>
<span>34分钟前</span>
<div class="reco-job-status">
<span>简历处理率:100%</span>
<span>平均处理:1天</span>
</div>
</div>
</div>
</div>
</li>
首先,寻找出<li> <\li>
标签,我们所需的信息都包含在这两个标签里面;
进一步分析,岗位信息和岗位链接信息都包含在class=”reco-job-title”的<a>
标签里面,通过.get_text (一种提取文本信息的方法) 获取岗位信息;
通过.get(“href”) ( 返回指定键的值,如果不存在返回默认值 ) 获取岗位链接;
地点的获取:可以看出地点信息包含在:1
<span class="nk-txt-ellipsis js-nc-title-tips job-address" data-title="上海"><i class="icon-map-marker"></i>上海</span>
因此,找到这个class对应的span,然后用get_text方法获取地点;
同样的方法,获取公司信息。
相应的python代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37def getJobInfo(page_content):
zhiwei=[]
company=[]
link=[]
data=[]
shixi_of = '🔴'+ '来自牛客网最新官方实习信息' + "\n" + '[机器喵自动获取,仅供参考]' + "\n" + "---------------------------------" + "\n"
data.append(shixi_of)
global i,j,k,m
job_li=page_content.findAll("li",{"class":"clearfix"})
# print(job_li)
for job_div in job_li:
job_zhiwei = job_div.findAll("a", {"class": "reco-job-title"})
for jobzw in job_zhiwei:
# zhiwei.append(jobzw.get_text())
global i
i='岗位:'+jobzw.get_text()+'\n'
link_1='https://www.nowcoder.com'+jobzw.get("href")
global k
k='详细信息:'+link_1+'\n'+'---------------------------------'
# link.append(link_1)
job_location=job_div.findAll("span",{"class":"nk-txt-ellipsis js-nc-title-tips job-address"})
for joblocation in job_location:
global m
m='地点:'+joblocation.get_text()+'\n'
job_company=job_div.findAll("div",{"class":"reco-job-com"})
for jobcom in job_company:
# company.append(jobcom.get_text())
global j
j='公司:'+jobcom.get_text().replace('\n','')+'\n'
data.append(i+j+m+k)
arr="".join(data)
# for h in data:
print(arr)
# print(h)
return data
range()方法和xrange()的区别
首先,程序中在获取每一页上面的信息时,用到了range方法循环url:
1 | for i in range(1, 6): |
range和xrange的区别
首先我们看看range: range([start,] stop[, step])
,根据start与stop指定的范围以及step设定的步长,生成一个序列。
注意这里是生成一个序列。
xrange的用法与range相同,即xrange([start,] stop[, step])
,根据start与stop指定的范围以及step设定的步长,他所不同的是xrange并不是生成序列,而是作为一个生成器,即他的数据生成一个取出一个。
所以相对来说,xrange比range性能优化很多,因为他不需要一下子开辟一块很大的内存,特别是数据量比较大的时候。
print问题
对于输出的信息,分别存在i,j,k,m中,以字符串的形式;
定义了一个data=[]数组,用来存储每次得到的信息1
2
3 data.append(i+j+m+k)
for h in data:
print(h)
最后的输出,是一条一条的,把每条信息都分开了(print出来并不明显,但是微信发送的时候消息就会很多)
1 | 🔴来自牛客网最新官方实习信息 |
如果想把所有的消息合为一条,经过查资料,找到了.join()方法,该方法用于将序列中的元素以指定的字符连接生成一个新的字符串。
str.join(元组、列表、字典、字符串)之后生成的只能是字符串;
所以,很多时候,可以用join()来转化为字符串;1
2arr="".join(data)
print(arr)
1 | 🔴来自牛客网最新官方实习信息 |