爬虫入门之牛客网官方实习网页练习~~~~
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  | 🔴来自牛客网最新官方实习信息  |