爬虫系列一


一切为了数据挖掘的准备
在中国大学MOOC网站上学习的北京理工大学嵩天老师的免费爬虫课程课件,简单易懂,感兴趣的戳 嵩天老师爬虫课程。侵删

一 requests库

1.1.requests库
>>> r=requests.get('http://www.baidu.com')
>>> r.status_code
200
>>> r.encoding='utf-8'
>>> type(r)
<class 'requests.models.Response'>
>>> r.text
1.2.requests函数
  • requests.request(method,url,**kwargs)
    • method:get/put/post/head/patch/delete/options
    • 参数:
      • params:字典或字典序列,作为参数增加到url中
      url?key1=value1&key2=value2
      
      • data:字典字节或文件,作为request内容
      • json:作为request的内容
      • headers:字典,头字段
        {‘user-agent’:‘Chrome/10’}
      • cookies:字典或cookiejar
      • auth:认证
      • files:传输文件
      fs = {'file':open('文件名','rb')}
      r = requests.request(url,file=fs)
      
      • timeout:,s为单位
      • proxies:字典类型,设定当问代理服务器,增加登陆认证.有效隐藏用户爬虫源的IP地址,防止反追踪
      pxs = {'http':'','https':''}
      

其他方法都用requests.request方法封装

  • requests.get(url,params=None,**kwargs),返回Response对象
    Request对象
  • head() 仅获得网页头信息的方法,用少量
>>> r = requests.head('http://www.baidu.com')
>>> r.headers
{'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform', 'Connection': 'Keep-Alive', 'Content-Encoding': 'gzip', 'Content-Type': 'text/html', 'Date': 'Wed, 27 Mar 2019 03:37:14 GMT', 'Last-Modified': 'Mon, 13 Jun 2016 02:50:04 GMT', 'Pragma': 'no-cache', 'Server': 'bfe/1.0.8.18'}
>>> r.text
''
  • post(),增加数据
data={'aaa':'haha'}
r=request.post(url,data)
  • put(),覆盖原有数据
  • patch(),向html网页提交局部修改的请求
  • delete(),提交删除请求
1.3.Response对象

属性:

  • r.status_code,http请求的返回状态,200连接成功,404失败
  • r.text,响应内容的字符串形式
  • r.encoding,http header中猜测的响应内容编码方式。如果header中不存在charser,认为编码默认iso-8859-1
  • r.apparent_encoding,从内容中分析出的响应内容编码方式
  • r.content,响应内容的二进制形式
  • r.headers,头部信息,返回网页的头信息
  • r.request,Request对象(r.request.headers)
1.4 Request对象,访问对象
  • headers属性,访问时的头信息,有User-Agent等
1.4.通用框架

网络连接有风险,需要处理异常

  • requests.ConnectionError,网络连接错误,DNS查询失败,拒绝连接
  • requests.HTTPError,HTTP错误一场
  • requests.URLRquired,URL确实
  • requests.TooManyRedirects,超过最大重定向次数,产生重定行异常,复杂链接访问时
  • requests.ConnectTimeout,远程连接服务器超时,仅指连接
  • requests.Timeout,请求URL超时,发出连接到获得

方法:

  • r.raise_for_status(),如果状态不是200,产生异常requests.HTTPError
def getHTMLText(url):
    try:
        r = requests.get(url)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return "产生异常"
1.5.HTTP协议

超文本出阿叔协议,基于“请求与响应”的无状态(前一次后后一次访问间无关系)的应用层协议。采用url做标识

  • url格式: hrrp://host[:port][path]

  • http协议对资源的操作

    • get:请求获取url位置的资源
    • head:请求获取url位置资源的相应消息报告,即获取该资源的头部信息
    • post:附加新数据,不改变原有资源
    • put:请求存储一个资源,覆盖原url位置资源
    • patch:请求局部更新url位置的资源,即改变该处资源的部分内容,可以节省网络带宽
    • delete:请求删除存储的资源

二 网络爬虫

2.1.爬虫尺寸
  • 小规模,数据量小,爬去速度不敏感,requests库
  • 中规模,规模大,速度敏感,Scrapy库,爬取系列网站
  • 大规模,搜索引擎,爬取速度关键,定制开发,爬取全网
2.2.爬虫的规范
  • 通过来源审查:http头部的User-Agent进行限制
    检查来访HTTP协议头的User-Agent域,之相应浏览器或友好爬虫的访问
  • 发布公告:Robost协议
    告知所有爬虫网站的爬取策略,要求爬虫遵守
2.3.Robots协议,网络爬虫排除标准
  • 作用:网站告知爬虫哪些页面可以抓取,哪些不行
  • 形式:在网站根目录下的robots.txt文件
  • 如果网站没有robots.txt,不限制爬虫
# *代表所有,/根目录
User-Agent:*   //对所有的用户
Disallow: /?*  //不能访问此目录下的资源
2.4.Robots协议的遵守方式
  • 使用:自动或人工识别robots.txt,再进行内容爬取
  • 约束性:建议非约束,但有法律风险。
  • 当类人类行为可不参考,例如访问量不大,时间短
2.5.练习
  • 当访问网页受限时,有可能没有遵守Robots协议,有可能对访问对象(通过request.headers中的User-Agent)受限(来源审查)
kv={'user-agent':'Mozilla/5,0'}  //假装来自网页
r = requests.get(url, headers=kv)
kv={'wd':'苹果的品种'}
r = request.get('http://www.baidu.com/s',params=kv)
r.status_code
r.request.url
len(r.text)
  • 网络图片的爬去和存储
    图片链接的格式 url/picture.jpg
import requests
import os
url='https://ss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=8ad822e9df00baa1a52c41bb7711b9b1/0b55b319ebc4b745564c5813c1fc1e178b8215de.jpg'
root='C:/Users/lenovo/Desktop'
path = root + url.split('/')[-1]
try:
    if not os.path.exists(root):
        os.mkdir(root)
    if not os.path.exists(path):
        r = requests.get(url)
        with open(f,'wb') as f:
            f.write(r.content)
            f.close()
            print('文件保存成功')
    else:
        print("文件已存在")
except:
    print("爬取失败")
url = 'http://m.ip138.com/ip.asp?ip='
r=requests.get(url + '202.204.80.112')

r.text最好约束长度[:500]

三 Beautiful Soup库入门

对HTML XML内容解析

>>> import requests
>>> from bs4 import BeautifulSoup
>>> r = requests.get('https://python123.io/ws/demo.html')
>>> r.status_code
200
>>> demo = r.text
>>> soup = BeautifulSoup(demo,"html.parser")
>>> print(soup.prettify())
<html>
 <head>
  <title>
   This is a python demo page
  </title>
 </head>
 <body>
  <p class="title">
   <b>
    The demo python introduces several python courses.
   </b>
  </p>
  <p class="course">
   Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
   <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">
    Basic Python
   </a>
   and
   <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">
    Advanced Python
   </a>
   .
  </p>
 </body>
</html>
3.1.BeautifulSoup库的基本元素

是解析、遍历、维护“标签树”的功能库

  • 引入
from bs4 import BeautifulSoup
  • 解析标签树
soup = BeautifulSoup('<html>data<html>','html.parser')
soup = BeautifulSoup(open('文件名.html'),'html.parser')
  • 解析器
    • ‘html.parser’, 需要安装bs4库
    • ‘lxml’, 安装 lxml库
    • ‘xml’,安装lxml库
    • ‘html5lib’,安装 heml5lib库
BeautifulSoup 类的基本元素
  • Tag,标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾
    • 获得标签
    # 只能获得第一个a元素
    >>> soup.a
    <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>
    
  • Name 标签的名字,<p>…</p>的名字是’p’
soup.a.name
soup.a.parent.name #父元素的名字
  • 标签的属性,字典形式组织,没有属性返回空字典
>>> soup.a.attrs
{'href': 'http://www.icourse163.org/course/BIT-268001', 'class': ['py1'], 'id': 'link1'}
>>> type(soup.a)
<class 'bs4.element.Tag'>
  • NavigableString,标签内非属性字符串,<>…</>中字符串。.string
>>> type(soup.p)
<class 'bs4.element.Tag'>
>>> type(soup.p.string)
<class 'bs4.element.NavigableString'>
  • Comment,标签内字符串注释部分,一种特殊的Comment类型
>>> newsoup = BeautifulSoup('<b><!--this is a comment--></b>','html.parser')
>>> newsoup.b
<b><!--this is a comment--></b>
>>> newsoup.b.string
'this is a comment'
>>> type(newsoup.b.string)
<class 'bs4.element.Comment'>

可以通过.string的类型判断是否是注释

3.2.基于bs4库的HTML内容遍历方法
标签树的下行遍历
  • .contents,子节点的列表
  • .children,子节点的迭代类型
  • .descendants,子孙节点的迭代类型,包含所有的子孙节点
标签树的上行遍历
  • .parent,父亲节点
  • .parents,先辈节点的迭代类型
标签树的平行遍历
  • next_sibling,下一个平行节点标签
  • previous_sibling,上一平行节点标签
  • next_sibilings,后续所有的平行节点标签
  • previous_siblings,前续所有的平行节点标签
3.3.html格式输出
  • prettify()方法,为标签后面添加换行符
soup.prettify()
soup.a.prettify()
  • bs4库将任何html输入都变成utf-8编码

四 信息的标记

标记后的信息可形成信息组织结构,增加了信息的维度。

  • xml
  • json
  • yaml:无类型键值对,通过缩进表示键值关系。
    • 用|表达整块数据.
    • 用:表示所属关系
    • 用-表示并列关系
    • #表示Comment
    key : value
    key : #Comment
    - value1
    - value2
    key : 
        subkey : subvalue
    
4.1.信息提取的一般方法
  • soup.find_all(name,attrs,recursive,string)
    for link in soup.find_all('a')
        print(link.get('href'))
    
    • name:标签名称的检索
    soup.find_all('a')
    soup.find_all(['a','b']) 
    soup.find_all(true) #所有标签
    import re
    soup.find_all(re.compile('b')) #以b开头
    
    • attrs:对标签属性的检索字符串
    soup.find_all(id='link')
    soup.find_all(id=re.compile('link')) #属性以link开头
    
    • recursive:是否对子孙全部检索,默认True;设为False时,之检索子节点
    • string:<></>中字符串区域的检索字符串
    soup.find_all(string=re.compile('python'))
    soup.find_all(string='python')
    
    • 简短形式
      () 等价于.find_all()
      soup() 等价于 soup.find_all()
  • <>.find() 只返回一个结果
  • find_parents(),返回列表类型
  • find_parent(),返回一个类型
  • find_next_siblings()
  • find_next_sibling()
  • find_previous_siblings()
  • find_previous_sibling()

五 练习

爬取"http://www.zuihaodaxue.cn/zuihaodaxuepaiming2018.html" 网页,先确定robots协议,即"http://www.zuihaodaxue.cn/robots.txt"存不存在。

import requests
import bs4 #使用标签类型定义
from bs4 import BeautifulSoup

def getHTMLText(url):
    try:
        r= requests.get(url,timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return""
    

def fillUnivList(ulist,html):
    soup = BeautifulSoup(html,'html.parser')
    for tr in soup.find('tbody').children:
        if isinstance(tr,bs4.element.Tag): #儿子有可能是<tr>标签或字符串类型
            tds = tr('td')
            ulist.append([tds[0].string,tds[1].string,tds[3].string])
    

def printUnivList(ulist,num):
    tplt= '{0:^10}\t{1:{3}^10}\t{2:^10}'
    print(tplt.format("排名","学校","打分",chr(12288))) #chr(12288)中文可以对齐
    for i in range(num):
        u = ulist[i]
        print(tplt.format(u[0],u[1],u[2],chr(12288)))

def main():
    uinfo = []
    url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html'
    html = getHTMLText(url)
    fillUnivList(uinfo,html)
    printUnivList(uinfo,20)
    
main()

猜你喜欢

转载自blog.csdn.net/liuerin/article/details/89001619