关于python:python爬虫保姆级教学urllib的使用以及页面解析

1.urllib库

1.1 根本应用

应用urllib来获取百度首页的源码

import urllib.request

# 1、定义一个url  就是你要拜访的地址
url = 'http://www.baidu.com'

# 2、模仿浏览器向服务器发送申请 response响应
response = urllib.request.urlopen(url)

# 3、获取响应中的页面的源码
content = response.read().decode('utf-8')

# 4、打印数据
print(content)

read办法,返回的是字节模式的二进制数据,咱们要将二进制的数据转换为字符串,需解码 : decode(‘编码的格局’)

1.2 1个类型和6个办法

import urllib.request

url = 'http://www.baidu.com'

# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(url)

# 一个类型:response是HTTPResponse的类型
print(type(response))

# 依照一个字节一个字节的去读
content = response.read()
print(content)

# 返回多少个字节
content = response.read(5)
print(content)

# 读取一行
content = response.readline()
print(content)

# 一行一行读取 直至完结
content = response.readlines()
print(content)

# 返回状态码  如果是200了 那么就证实咱们的逻辑没有错
print(response.getcode())

# 返回的是url地址
print(response.geturl())

# 获取是一个状态信息
print(response.getheaders())

一个类型:HTTPResponse

六个办法: read、readline、readlines、getcode、geturl、getheaders

1.3 下载

import urllib.request

# 下载网页
url_page = 'http://www.baidu.com'

# url代表的是下载的门路  filename文件的名字
urllib.request.urlretrieve(url_page,'baidu.html')

# 下载图片
url_img = 'https://img1.baidu.com/it/u=3004965690,4089234593&fm=26&fmt=auto&gp=0.jpg'
urllib.request.urlretrieve(url= url_img,filename='lisa.jpg')

# 下载视频
url_video = 'https://vd3.bdstatic.com/mda-mhkku4ndaka5etk3/1080p/cae_h264/1629557146541497769/mda-mhkku4ndaka5etk3.mp4?v_from_s=hkapp-haokan-tucheng&auth_key=1629687514-0-0-7ed57ed7d1168bb1f06d18a4ea214300&bcevod_channel=searchbox_feed&pd=1&pt=3&abtest='

urllib.request.urlretrieve(url_video,'hxekyyds.mp4')

在python中,能够写变量的名字,也能够间接写值

1.4 申请对象的定制

import urllib.request

url = 'https://www.baidu.com'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

# 因为urlopen办法中不能存储字典 所以headers不能传递进去
# 申请对象的定制
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf8')
print(content)

1.5 get申请的quote办法

get申请参数,如果是中文,须要对中文进行编码,如上面这样,如果不编码会报错。

需要 获取 https://www.baidu.com/s?wd=周杰伦的网页源码

编码后如下: https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6

import urllib.request
import urllib.parse

url = 'https://www.baidu.com/s?wd='

# 申请对象的定制为了解决反爬的第一种伎俩
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

# 将周杰伦三个字变成unicode编码的格局,须要依赖于urllib.parse
name = urllib.parse.quote('周杰伦')

# 将转码后的字符串拼接到门路前面
url = url + name

# 申请对象的定制
request = urllib.request.Request(url=url,headers=headers)

# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(request)

# 获取响应的内容
content = response.read().decode('utf-8')

# 打印数据
print(content)

quote实用于将中文转码成Unicode编码

1.6 get申请的urlencode办法

urlencode利用场景:多个参数的时候。如下

https://www.baidu.com/s?wd=周杰伦&sex=男

# 获取https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7的网页源码

import urllib.request
import urllib.parse

base_url = 'https://www.baidu.com/s?'

data = {
    'wd':'周杰伦',
    'sex':'男',
    'location':'中国台湾省'
}

new_data = urllib.parse.urlencode(data)

# 申请资源门路
url = base_url + new_data

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

# 申请对象的定制
request = urllib.request.Request(url=url,headers=headers)

# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(request)

# 获取网页源码的数据
content = response.read().decode('utf-8')

# 打印数据
print(content)

1.7 post申请

import urllib.request
import urllib.parse

url = 'https://fanyi.baidu.com/sug'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

data = {
    'kw':'spider'
}

# post申请的参数,必须要进行编码
data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request(url=url,data=data,headers=headers)

# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(request)

# 获取响应的数据
content = response.read().decode('utf-8')

# 字符串--》json对象
import json
obj = json.loads(content)
print(obj)

post申请的参数 必须要进行编码:data = urllib.parse.urlencode(data)
编码之后 必须调用encode办法 : data = urllib.parse.urlencode(data).encode(‘utf-8’)
post的申请的参数,是不会拼接在url的前面的 ,而是须要放在申请对象定制的参数中:
request = urllib.request.Request(url=url,data=data,headers=headers)

1.8 异样

import urllib.request
import urllib.error

url = 'http://www.doudan1.com'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

try:
    request = urllib.request.Request(url = url, headers = headers)
    response = urllib.request.urlopen(request)
    content = response.read().decode('utf-8')
    print(content)
except urllib.error.HTTPError:
    print('零碎正在降级。。。')
except urllib.error.URLError:
    print('我都说了 零碎正在降级。。。')

1.9 handler

为什么要学习handler?

  • urllib.request.urlopen(url) 不能定制申请头
  • urllib.request.Request(url,headers,data) 能够定制申请头
  • Handler:定制更高级的申请头(随着业务逻辑的简单 申请对象的定制曾经满足不了咱们的需要,动静cookie和代理不能应用申请对象的定制)
# 需要 应用handler来拜访百度  获取网页源码

import urllib.request

url = 'http://www.baidu.com'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

request = urllib.request.Request(url = url,headers = headers)

# handler   build_opener  open

#(1)获取hanlder对象
handler = urllib.request.HTTPHandler()

#(2)获取opener对象
opener = urllib.request.build_opener(handler)

# (3) 调用open办法
response = opener.open(request)
content = response.read().decode('utf-8')
print(content)

1.10 代理

为什么须要代理?因为有的网站是禁止爬虫的,如果用实在的ip去爬虫,容易被封掉。

import urllib.request

url = 'http://www.baidu.com/s?wd=ip'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

# 申请对象的定制
request = urllib.request.Request(url = url,headers= headers)

# 模仿浏览器拜访服务器
# response = urllib.request.urlopen(request)

proxies = {
    'http':'118.24.219.151:16817'
}

# handler  build_opener  open
handler = urllib.request.ProxyHandler(proxies = proxies)
opener = urllib.request.build_opener(handler)
response = opener.open(request)

# 获取响应的信息
content = response.read().decode('utf-8')

# 保留
with open('daili.html','w',encoding='utf-8')as fp:
    fp.write(content)

代理能够应用:快代理。能够应用代理池来代替一个代理

2.解析技术

2.1 xpath

xpath装置及加载

1.装置lxml库

pip install lxml ‐i https://pypi.douban.com/simple

2.导入lxml.etree

from lxml import etree

3.etree.parse() 解析本地文件

html\_tree = etree.parse(‘XX.html’)

4.etree.HTML() 服务器响应文件

html\_tree = etree.HTML(response.read().decode(‘utf‐8’)

5.解析获取DOM元素

html\_tree.xpath(xpath门路)

依照xpath的chrome插件,应用 ctrl + shift + x 关上插件

xpath根本语法

1.门路查问

//:查找所有子孙节点,不思考层级关系
/ :找间接子节点

2.谓词查问

//div[@id]
//div[@id=“maincontent”]

3.属性查问

//@class

4.含糊查问

//div[contains(@id, “he”)]
//div[starts‐with(@id, “he”)]

5.内容查问

//div/h1/text()

6.逻辑运算

//div[@id=“head” and @class=“s\_down”]
//title | //price

示例:

from lxml import etree

# xpath解析本地文件
tree = etree.parse('test.html')

# 查找ul上面的li
li_list = tree.xpath('//body/ul/li')

# 查找所有有id的属性的li标签,text()获取标签中的内容
li_list = tree.xpath('//ul/li[@id]/text()')

# 找到id为l1的li标签  留神引号的问题
li_list = tree.xpath('//ul/li[@id="l1"]/text()')

# 查找到id为l1的li标签的class的属性值
li = tree.xpath('//ul/li[@id="l1"]/@class')

# 查问id中蕴含l的li标签
li_list = tree.xpath('//ul/li[contains(@id,"l")]/text()')

# 查问id的值以l结尾的li标签
li_list = tree.xpath('//ul/li[starts-with(@id,"c")]/text()')

#查问id为l1和class为c1的
li_list = tree.xpath('//ul/li[@id="l1" and @class="c1"]/text()')

li_list = tree.xpath('//ul/li[@id="l1"]/text() | //ul/li[@id="l2"]/text()')

2.2 JsonPath

JsonPath只能解析本地文件。

jsonpath的装置及应用

pip装置:

pip install jsonpath

jsonpath的应用:

obj = json.load(open(‘json文件’, ‘r’, encoding=‘utf‐8’))
ret = jsonpath.jsonpath(obj, ‘jsonpath语法’)

示例:

{
  "store": {
    "book": [
      {
        "category": "修真",
        "author": "六道",
        "title": "坏蛋是怎么练成的",
        "price": 8.95
      },
      {
        "category": "修真",
        "author": "天蚕土豆",
        "title": "斗破天穹",
        "price": 12.99
      },
      {
        "category": "修真",
        "author": "唐家三少",
        "title": "斗罗大陆",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      {
        "category": "修真",
        "author": "南派三叔",
        "title": "星辰变",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "author": "老马",
      "color": "彩色",
      "price": 19.95
    }
  }
}

解析下面的json数据

(https://links.jianshu.com/go?…)

import json
import jsonpath

obj = json.load(open('jsonpath.json','r',encoding='utf-8'))

# 书店所有书的作者
author_list = jsonpath.jsonpath(obj,'$.store.book[*].author')

# 所有的作者
author_list = jsonpath.jsonpath(obj,'$..author')

# store上面的所有的元素
tag_list = jsonpath.jsonpath(obj,'$.store.*')

# store外面所有货色的price
price_list = jsonpath.jsonpath(obj,'$.store..price')

# 第三个书
book = jsonpath.jsonpath(obj,'$..book[2]')

# 最初一本书
book = jsonpath.jsonpath(obj,'$..book[(@.length-1)]')

#  后面的两本书
book_list = jsonpath.jsonpath(obj,'$..book[0,1]')
book_list = jsonpath.jsonpath(obj,'$..book[:2]')

# 条件过滤须要在()的后面增加一个?
#   过滤出所有的蕴含isbn的书。
book_list = jsonpath.jsonpath(obj,'$..book[?(@.isbn)]')

# 哪本书超过了10块钱
book_list = jsonpath.jsonpath(obj,'$..book[?(@.price>10)]')

2.3 BeautifulSoup

根本介绍

  • BeautifulSoup简称:bs4
  • 什么是BeatifulSoup? BeautifulSoup,和lxml一样,是一个html的解析器,次要性能也是解析和提取数据
  • 优缺点

    毛病:效率没有lxml的效率高
    长处:接口设计人性化,使用方便

装置以及创立

  • 装置

    pip install bs4 -i https://pypi.douban.com/simple

  • 导入

    from bs4 import BeautifulSoup

  • 创建对象

    • 服务器响应的文件生成对象

      soup = BeautifulSoup(response.read().decode(), ‘lxml’)

    • 本地文件生成对象

      soup = BeautifulSoup(open(‘1.html’), ‘lxml’)

留神:默认关上文件的编码格局gbk所以须要指定关上编码格局

节点定位

1.依据标签名查找节点

soup.a # 只能找到第一个a
soup.a.name
soup.a.attrs

2.函数

  • find(返回一个对象)

    find(‘a’):只找到第一个a标签

    find(‘a’, title=‘名字’)

    find(‘a’, class\_=‘名字’)

  • find\_all(返回一个列表)

    find\_all(‘a’) :查找到所有的a

    find\_all([‘a’, ‘span’]) 返回所有的a和span

    find\_all(‘a’, limit=2) 只找前两个a

  • select(依据选择器失去节点对象)【☆☆☆】

    • element:p
    • .class:.firstname
    • #id:#firstname
    • 属性选择器
      [attribute]:li = soup.select(‘li[class]’)
      [attribute=value]:li = soup.select(‘li[class=“hengheng1”]’)
    • 层级选择器:
      div p 后辈选择器
      div>p 子代选择器:某标签的第一级子标签
      div,p div或p标签的所有的对象

节点信息

  • 获取节点内容:实用于标签中嵌套标签的构造

    obj.string

    obj.get\_text()【举荐】

  • 节点的属性

    tag.name:获取标签名

    tag.attrs:将属性值作为一个字典返回

  • 获取节点属性

    obj.attrs.get(‘title’)【罕用】

    obj.get(‘title’)

    obj[‘title’]

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div>
        <ul>
            <li id="l1">张三</li>
            <li id="l2">李四</li>
            <li>王五</li>
            <a href="" id="" class="a1">尚硅谷</a>
            <span>嘿嘿嘿</span>
        </ul>
    </div>
    <a href="" title="a2">百度</a>
    <div id="d1">
        <span>
            哈哈哈
        </span>
    </div>
    <p id="p1" class="p1">呵呵呵</p>
</body>
</html>

应用BeautifulSoup解析下面的html

from bs4 import BeautifulSoup

# 默认关上的文件的编码格局是gbk,所以在关上文件的时候须要指定编码
soup = BeautifulSoup(open('bs4的根本应用.html',encoding='utf-8'),'lxml')

# 依据标签名查找节点,找到的是第一个符合条件的数据
print(soup.a)
# 获取标签的属性和属性值
print(soup.a.attrs)

# bs4的一些函数
# (1)find:返回的是第一个符合条件的数据
print(soup.find('a'))

# 依据title的值来找到对应的标签对象
print(soup.find('a',title="a2"))

# 依据class的值来找到对应的标签对象  留神的是class须要增加下划线
print(soup.find('a',class_="a1"))

# (2)find_all  返回的是一个列表,并且返回了所有的a标签
print(soup.find_all('a'))

# 如果想获取的是多个标签的数据 那么须要在find_all的参数中增加的是列表的数据
print(soup.find_all(['a','span']))

# limit的作用是查找前几个数据
print(soup.find_all('li',limit=2))

# (3)select(举荐)
# select办法返回的是一个列表,并且会返回多个数据
print(soup.select('a'))

# 能够通过.代表class  咱们把这种操作叫做类选择器
print(soup.select('.a1'))
print(soup.select('#l1'))

# 属性选择器:通过属性来寻找对应的标签
# 查找到li标签中有id的标签
print(soup.select('li[id]'))

# 查找到li标签中id为l2的标签
print(soup.select('li[id="l2"]'))

# 层级选择器
#  后辈选择器:找到的是div上面的li
print(soup.select('div li'))

# 子代选择器:某标签的第一级子标签
print(soup.select('div > ul > li'))

# 找到a标签和li标签的所有的对象
print(soup.select('a,li'))

# 获取节点内容
obj = soup.select('#d1')[0]

# 如果标签对象中,只有内容,那么string和get_text()都能够应用
# 如果标签对象中,除了内容还有标签,那么string就获取不到数据 而get_text()是能够获取数据
# 举荐应用get_text()
print(obj.string)
print(obj.get_text())

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理