Python 爬虫学习

网络爬虫: 一种按照一定规则,自动抓取互联网信息的程序或者脚本, 爬虫的本质是模拟浏览器打开网页,获取网页中我们想要的那部分数据

Python为什么适合爬虫:
        Python的脚本特性, Python易于配置, 对字符的处理液非常灵活, 加上Python拥有丰富的网络抓取模块.

Python爬虫的组成部分

主要包含五个部分: 调度器, URL管理器, 网页下载器, 网页解析器, 应用程序(爬取的有价值数据)

调度器:相当于一台电脑的CPU,主要负责调度URL管理器,下载器,解析器之间的协调工作。

URL管理器:包括待爬取的URL地址和一爬取的URL地址,防止重复抓取URL和循环抓取URL,实现URL管理器主要用三种方式,通过内存,数据库,缓存数据库来实现。

网页下载器:通过传入一个URL地址来下载,将网页转换成一个字符串,网页下载器有urllib(Python官方内置标准库)包括需要登陆,代理和cookie,requests(第三方包)。

网页解析器:将一个网页字符串进行解析,可以按照我们的要求来提取出我们最有用的信息,也可以根据DOM树的解析方式来解析。网页解析器有正则表达式(只管,将网页转换成字符串通过模糊匹配的方式来提取有价值的信息,当文档比较复杂的时候,该方法提取数据的时候就会非常困难),html.parser(Python自带),beautifulsoup(第三方插件,可以解析xml和HTML),html.parser和beautifulsoup以及lxml都是以DOM树的方式进行解析的。

应用程序:就是从网页中提取的有用数据组成的一个应用。

URI和URL的概念

URL

在1989年,网络发明人蒂姆·比纳斯-李 就提出了网站的三大支柱:

  1. URL,跟踪Web文档的地址系统
  2. HTTP,一个传输协议,以便在给定URL时查找文档
  3. HTML,允许嵌入超链接的文档格式

web的最初目的是提供一种简单的方式来访问,阅读和浏览文本文档。从那时起,网络已经发展到提供图像,视频和二进制数据的访问,但是这些改进几乎没有改变三大支柱。

在web之前,很难访问文档并从一个文档跳转到另一个文档。WWW(World Wide Web)简称3W,使用同一资源定位符(URL)来标志WWW上的各种文档

完整的工作流程:

1) Web用户使用浏览器(指定URL)与web服务器建立连接,并发送浏览请求。

2) Web服务器吧URL转换为文件路径,并放回信息给Web浏览器。

3) 通讯完成,关闭连接。

HTTP:超文本传送协议(HTTP)是在客户程序(如浏览器)与WWW服务器之间进行交互所使用的协议。HTTP使用同一资源标识符(Uniform Resource Identifiers, URI)来传输数据和创建使用,它使用TCP连接进行可靠传输,服务器默认监听在80端口。

URL的组成:

1)协议部分:他表示浏览器必须使用的协议来请求资源(协议是在计算机网络中交换或传输数据的一套方式),通常对于网络,协议是HTTP和HTTPS。

2)域名部分(www.baidu.com):一个URL中,域名部分也可以直接使用IP地址。

3)端口部分(80):域名和端口之间使用 ‘:’ 作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口(默认端口可以省略,默认端口可以修改)。

4)资源路径:资源路径包含,虚拟网络部分和文件名部分

        虚拟目录部分( /path/to/ )从域名后第一个“/”到最后一个“/”之间的部分,是虚拟目录部分,虚拟目录也不是一个URL必须的部分

        文件名部分(mylike.html)从域名最后一个“/” 开始到“?”为止,是文件名部分

5)参数部分: 从?开始到 # 之间,参数可以有多个,之间的间隔符是&
6)锚部分: #xxx 一种具体的URI,即URL可以用来标识一个资源,并且还指明了如何locate(定位)这个资源

引入模块

模块(module):用来从逻辑上组织Python代码(变量,函数,类),本质就是py文件,提供代码的可维护性,Python使用import来导入模块

#导入内置模块
import sys

#导入标准库
import os

#导入第三方库(需要安装:pip install bs4)
import bs4 #导入整个模块
from bs4 import BeautifulSoup #导入指定模块的部分到当前工作空间

urllib库

1. request模块:HTTP请求模块,可以用来模拟发送请求,只需要传入URL以及额外参数,就可以模拟浏览器访问网页

# 语法
"""
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
"""


"""
参数说明:
url: 请求的url,也可以是request对象
data: 请求的data,post请求会用到
timeout:链接超时时间
cafile和capath:用于 HTTPS 请求中,设置 CA 证书及其路径           // 没搞懂啥意思
cadefault:忽略*cadefault*参数;                                 // 没搞懂啥意思
context:如果指定了*context*  则它必须是一个ssl.SSLContext实例    // 没搞懂啥意思
"""

"""
返回值说明:
urlopen() 返回对象HTTPResponse提供的方法和属性:
read(), readline(),readlines(),fileno(),close() 对HTTPResponse类型数据进行操作;
info() 返回HTTPMessage对象,表示远程服务器 返回的头信息
getcode() 返回HTTP状态码
geturl() 返回请求的url
getheaders() 相应的头部信息
status 返回的状态码
reason 返回状态的详细信息
"""

def url_test():
    url = "http://www.baidu.com"    # 拿百度测试
    response = urllib.request.urlopen(url)    # get请求
    print(f'response: {response}') # <http.client.HTTPResponse object at 0x0000019484923580>
    # 读取响应体
    print(f'响应体:{response.read()}') # 调用read方法得到的是bytes对象
    print(f'HTTP版本号: {res.version}')  #HTTP版本号
    print(f'响应码(.getcode()): {res.getcode()}')  # 获取响应码
    print(f'响应码(.status): {res.status}')  # 获取状态 status
    print(f'获取响应描述字符串(.reason): {res.reason}')
    print(f'获取实际请求的页面URL: {res.geturl()}')  # 防止重定向
    print(f'获取响应头信息(字符串):\n{res.info()}')  # 字符串
    print(f'获取响应头信息(数组): {res.getheaders()}')  # 数组

    print(f'获取特定响应头信息ContentType: {res.getheader(name="Content-Type")}')  # 获取特定响应头信息ContentType
    


# 超时时间测试
def time_out():
    url = "http://www.baidu.com"
    try:
        res = urllib(url,timeout=0.01)
        print(res)
    except urllib.errorURLError as e:
        # error模块
        # uillib.error模块为urllib。request所引发的异常定义了异常类,基础异常类是URLError
        if hasattr(e, 'code'):
            print(f'time_out: {e.code}')
        if hasattr(e, 'reason'):
            print(f'reason: {e.reason}')
        print(f'Time Out: {e}')


# 伪装heaaders
def headers_customer():
    url = "http://douban.com"
    headers = {
        "User_Agent" : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }    
    req = urllib.request.Request(url, headers=headers)
    print(req)
    print(urllib.request.urlopen(url).read().getcode('utf-8'))

# urllib.request.urlretrieve()
# 直接将远程的数据下载到本地

"""
语法:
urlretrieve(url, filename=None, reporthook=None, data=None)
url: 网址地址
reporthook:回调函数,当连接上服务器,以及相应的数据块传输完毕时会触发该回调,可以利用这个回调函数来显示当前的下载进度
data: 指post到服务器的数据,该方法返回一个包含两个元素的(filename,headers)元组,filename表示保存到本地的路径,header表示服务器的响应头
"""


def down_load()
    url = "http://baidu.com"
    filename = "D:\\down\\one.index"
    urllib.request.urlretrieve(url, fileName, call_back)


def call_back(blocknum, blocksize, totalsize) {
    if totalsize == 0:
        percent = 0
    else:
        percent = blocknum * blocksize / totalsize
    if percent > 1.0:
        percent = 1.0
    percent = percent * 100
    print("download : %.2f%%" % percent)
}

Beautiful Soup 4库

给项目添加Beautiful Soup库

# 引入Beautiful Soup 4库
from bs4 import BeautifulSoup

BeautifulSoup将一个复杂的HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象归纳为4中,Tag. NavigableString, Beautifulsoup. Comment

Tag对象和HTML原生文档中的tag相同

Tag可能包含多个字符串或其他的Tag,这些都是这个Tag的子节点

Tag的名字,操作文档书最简单的方法就是利用tag的name,如果想要获取<header>标签,只要用soup.head

通过 . 获取属性的方法只能获取到当前名字的第一个Tag, 例如有多个div标签,则只能获取到文档树结构中的第一个div标签

如果想要获取所有的标签,或是比通过名字获取内容更复杂的方法时,就需要用到 搜索文档树 的方法

例: find_all() -> soup.find_all('div')         # 查找子节点中所有的div Tag

from bs4 import BeautifulSoup
def bs4_test(text):
    soup1 = BeautifulSoup(text, 'lxml')
    # BeautifulSoup将复杂的HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象归纳为4种:Tag,NavigableString,BeautifulSoup,Comment
    # Tag对象和XML或HTML原生文档中的tag相同
    # tag可能包含多个字符串或其他的tag,这些都是这个Tag的子节点。Beautiful Soup 提供了许多查找和操作子节点的方法。
    # Beautiful Soup中字符串节点不支持这些属性,因为字符串没有子节点。
    # Tag的名字,操作文档书最简单的方法就是利用tag的name,如果想要获取<header>标签,只要用soup.head
    # 通过.获取属性的方法只能获取到当前名字的第一个tag, 例如有多个div标签,则只能获取到文档树结构中的第一个div标签
    # 如果想要获取所有的标签,或是比通过名字获取内容更复杂的方法时,就需要用到 搜索文档树 的方法
    # 例: find_all()  ->   soup.find_all('div')
    # .content / .children
    # Tag的 .content 属性可以将tag的全部子节点以列表的方式输出
    # body下的contents列表
    # print(soup1.body.contents)
    # Tag的 .children,展示节点下所有的子节点
    num = 0
    for chi in soup1.body.children:
        num = num + 1
        print(f"计数:{num}", chi)
    # .descendants 会对节点的子孙节点进行递归循环
    num2 = 0
    for chi2 in soup1.body.descendants:
        num2 = num2 + 1
        for chi4 in chi2.stripped_strings:  # 去除多余的空格和空行
            print(f".stripped_strings方法:{chi4}")
        # print(f"计数:{num2}")
        # print(chi2)
        # print(f"计数:{num2}")
    print(f'.get_txt()方法:{soup1.get_text()}')
    # 如果节点下面只包含一个 NavigableString 类型的子节点,那么这个tag可以使用.string得到子节点
    # 如果节点下面只有一个子节点,那么这个tag也可以使用.string方法,输出结果与当前唯一子节点的.string结果相同
    # 如果节点下面包含多个子节点,则输出None
    # for chi3 in soup1.find_all('li'):
    #     for chi4 in chi3.stripped_strings:  # 去除多余的空格和空行
    #         print(f".stripped_strings方法:{chi4}")
    # 如果tag中包含多个字符串,可以使用.strings来循环获取
    # 如果字符串的空格空行,可以使用.stripped_strings去除多余空白内容

    # 父节点:
    # 每个tag或字符串都有父节点:包含当前内容的tag

re库

正则表达式

# 正则表达式RE模块 安装方式通bs4模块
import re

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值