欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

爬虫: requests, Beautiful Soup, 正则

程序员文章站 2022-07-13 12:59:43
...

requests库:请求

robots.txt:爬虫排除标准

Beautiful Soup:解析HTML页面

re:正则表达式

Scrapy框架

IDE

IDLE:自带

SublimeText:专业

Wing:调试功能,多人开发

Visual Studio & PTVS, PyCharm

数据分析,科学计算:Canop, Anaconda

Request库

r = requests.request(url, params=None, **kwargs)

Request——Response

​ 1. Response属性:

status_code:200表示成功

text,url

encoding:如果header中不存在charset,则认为ISO-8859-1

apparent_encoding:备选编码(内容分析)

content:二进制形式,response.content.decode('utf-8')代替text

​ 2. 异常:

ConnectionError:连接错误

HTTPError

URLRequired:url缺失

TooMuchRedirects:重定向异常

ConnectTimeout:连接超时

Timeout:超时

r.raise_for_status(), 不是200则引发HTTPError异常

try:
    r = requests.get(url, timeout=30)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    return r.text
except:
    return "产生异常"

​ 3. HTTP协议:超文本传输协议,请求与相应模式,无状态协议,URL作为标识

​ 操作:GET, HEAD, POST, PUT, PATCH, DELETE

​ URL:http://host[:post][path],存取资源的Internet路径,对应数据资源

​ host:主机域名或IP

​ port:端口号,缺省端口80

​ path:路径

**kwargs参数 说明
params 字典、字节序列,作为参数增加到url中
data 字典、字节序列、文件对象,作为Request的内容POST
json JSON格式的数据,作为Request的内容
headers 字典,HTTP定制头,模拟浏览器
cookies 字典,CookieJar,Request中的cookie
auth 元组,支持HTTP认证功能
files 字典类型,传输文件
timeout 设定超时时间,秒为单位
proxies 字典类型,设定访问代理服务器,可以增加登录认证(防追踪)
allow_redirects True/False,重定向开关
stream 获取内容立即下载开关,True/False
verify 认证SSL证书开关,True/False
cert 本地SSL证书路径

属性:‘r.request.’ + headers,url

request.get(url, params=None, **kwargs)

request.head(url, **kwargs)

request.post(url, data=None,json=None, **kwargs)

request.put(url, data=None, **kwargs)

request.patch(url, data=None, **kwargs)局部修改

request.delete(url, **kwargs)

协议

  1. 问题

    ​ 规模:

    ​ 小规模,网页 Requests

    ​ 中规模,网站,系列网站,Scrapy

    ​ 大规模,定制开发,全网

     限制:来源审查(User-Agent),Robots协议
    
  2. Robots协议

    在根目录:/robots.txt

    User-agent: *
    Disallow: /
    

    ​ 遵守方式:爬虫自动识别或先看看(类人行为可考虑不遵守)

import requests
url = 'https://www.amazon.cn/gp/product/B01M8L5Z2Y'
try:
    r = requests.get(url)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[:1000])
except:
    print('Fail')
    

# 错误分析
r.encoding = r.apparent_encoding
r.request.headers


# 假装是个浏览器
import requests
url = 'https://www.amazon.cn/gp/product/B01M8L5Z2Y'
try:
    kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url, headers=kv)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[:1000])
except:
    print('Fail')

浏览器关键词

import requests
kw = {'wd':'python'}
kv = {'user-agent': 'Mozilla/5.0'}
r = requests.get('http://www.baidu.com/s', params=kw, headers=kv)
r.status_code
r.request.url

图片爬取:确定文件格式

import requests
path = r'C:\Users\Desktop'
url = 'https://cdn.sspai.com/2020/04/19/cb225d96e4a20faf87aff067f83f2268.png'
r = requests.get(url)
r.status_code

with open(path, 'wb') as f:
    f.write(r.content)
    f.close()

ip归属地址查询:

import requests
url = 'http://m.ip138.com/ip.asp?ip='
ip = '...'
r = requests.get(url + ip)
r.status_code
# 不行就改一下headers

HTML解析器:Beautiful Soup

HTML解析库:

BeautifulSoup解析器 使用方法 条件
bs4的HTML解析器 BeautifulSoup(mk, ‘html.parser’) bs4
lxml的HTML解析器 BeautifulSoup(mk, ‘lxml’) lxml
lxml的XML解析器 BeautifulSoup(mk, ‘xml’) lxml
html5lib的解析器 BeautifulSoup(mk, ‘html5lib’) html5lib

pip install beautifulsoup4

from bs4 import BeautifulSoup
soup = BeautifulSoup(r.text, 'html.parser')
print(soup.prettify())

soup.a 返回a标签,多个标签只返回第一个

​ 解析器:

解析器 使用方法 特点,要求
python标准库 BeautifulSoup(r.text, ‘html.parser’) python内置,容错能力强
lxml HTML BeautifulSoup(r.text, ‘lxml’) 要求按照C语言,容错能力强,速度块
lxml XML BeautifulSoup(r.text, [‘lxml’, ‘xml’]) 要求按照C语言,支持XML
html5lib BeautifulSoup(r.text, ‘html5lib’) 容错能力最强,浏览器方式解析

​ 基本元素:

BeautifulSoup的基本元素 说明
Tag 最基本的信息组织单位,<>和</>开头和结尾
Name <p>, 'p’就是名字,<tag>.name<tag>.parent.ame
Attributes <p class=’…’>的class=’…’,属性,字典形式,<tag>.attrs
NavigableString <>…</>中的…,非属性字符串<tag>.string,
strings(子孙)生成器形式,stripped_strings非空白字符,get_text子孙,不是列表形式
Comment 注释部分
  1. 内容遍历方法
    1. 下行遍历:contents(子),迭代:children(子),descendants(子孙所有)

    2. 上行遍历:parent(父),迭代:parents(所有先辈)

    3. 平行遍历(同一个父标签):next_sbling, previous_sibling

      ​ 迭代:next_sblings, previous_siblings

      ​ 得到的不一定是标签类型

# head标签的子标签
soup.head.contents
# 子标签数目
len(soup.head.contents)
# 第二个子标签
soup.head.contents[1]

# 上行遍历
soup = BeautifulSoup(r.text, 'html.parser')
for parent in soup.parents:
    if parent is None:
        print(parent)	#soup本身
    else:
        print(parent.name)
  1. 输出:print(soup.prettify())每个标签后加/n,utf-8编码

信息标记的三种形式

​ HTML:通过<>…</>标签形式组织不同类型的信息

XML:和HTML类似,标签为主(基于HTML)(internet交互)

<name>...</name>, <name />, <!-- -->

JASON:键值对,字符时:键值都要有“”(代码一部分,但无注释)

"key":"value", "key":["value1", "value2"], "key":{"subkey":"subvalue"}

YAML:无类型键值对,无“”,缩进表达所属,并列前-,整块|,注释#(配置文件)

key:value, key:#Comment

信息提取方法:遍历、直接搜索关键信息,(和re同用)

​ 融合:例如:提取HTML中所有URL:找到所有a标签,解析提取href链接内容

1. find_all(name, attrs, recursive, string, **kwargs,limit)

​ attrs属性,recursive子孙默认True,string字符串,limit获取几个

​ 简写形式:

<tag>(..) = <tag>.find_all(..)

soup(..) = soup.find_all(..)

​ 扩展方法:

<>.find():只返回一个结果

<>.find_parents():返回先辈列表。<>.find_parent()

<>.find_next_siblings()<>.find_next_sibling()

<>.find_previous_siblings()<>.find_previous_sibling()

for link in soup.find_all('a'):
    print(link.get('href'))
   

from bs4 import BeautifulSoup
html="""
    ...
"""
soup = BeautifulSoup(html, 'lxml')
# 1.获得所有tr
tr = soup.find_all('tr')
# 2.第二个tr
tr2 = soup.find_all('tr', limit =2)[1]
# 3.class=even的tr,class_以便做区分,不然报错
tr_even = soup.find_all('tr', class_='even')
# 4.id='test',class='test'的tr,也可attrs={}
tr_22 = soup.find_all('tr', id='test', class_='text')
# 5.所有tr的href属性
trs = soup.find_all('tr')
for tr in trs:
    tr_href = tr['href']
    # 或者
    tr_href_2 =tr.attrs['href']
# 6.所有tr纯文本
trs = soup.find_all('tr')
for tr in trs:
    tr_info = list(tr.strings) #所有非标签字符串,其他应用string
    

2. select

css选择器:必需记住的选择符

p{…}对标签p定样式

# 标签名查找
print(soup.select('a'))
# 类名查找,class='sister'
print(soup.select('.sister'))
#查id,在id前加#,id='link1'
print(soup.select('#link1'))
# 组合查找,空格分开,或者,子标签>分隔
#不能同时提取id和class
print(soup.select('p #link1'))
print(soup.select('head > title'))
# 属性查找
print(soup.select('a[herf="..."]'))

3. 正则

# 正则
import re
for tag in soup.find_all(re.compile('b')):
    print(tag.name)

soup.find_all(True)  # 所有标签
# 含有course属性的p标签
soup.find_all('p', 'course')
#含有id='link1'属性的标签
soup.find_all(id='link1')

实例:爬取大学排名

		1. 获取网页内容:getHTMLText()
		2. 提取信息到适当的数据结构:fillUnivList()
		3. 展示输出结果:printUnivList()
from bs4 import BeautifulSoup
import bs4
import requests


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):  # 是否是标签
            tds = tr('td')
            ulist.append([tds[0].string, tds[1].string, tds[3].string])


def printUnivList(ulist, num):
    tplt = "{0:^10}\t{1:{3}^12}\t{2:^10}"
    print(tplt.format('排名', '学校名称', '总分', chr(12288)))
    for i in range(num):
        u = ulist[i]
        print(tplt.format(u[0], u[1], u[2], chr(12288)))


def mian():
    uinfo = []
    url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
    html = getHTMLText(url)
    fillUnivList(uinfo, html)
    printUnivList(uinfo, 20)

mian()

中文对齐问题:chr(12288)

正则:re库

常用函数

raw string类型(不包含转义符):r'text', r'[1-9]\d{5}'

re库常用功能函数 说明
re.search() 第一个位置,返回match对象(在一个字符串中)
re.match() 开始位置器匹配,返回match(在一个字符串中)
re.findall() 所有匹配的,列表返回全部字符串
re.split() 按匹配结果分割,返回列表(在一个字符串中)
参数maxsplit=0最大分割数
re.finditer() 搜索字符串,返回匹配结果的迭代,match对象
re.sub() 替换,(在一个字符串中)
参数:repl:替换的,count=0几次。prt

re.search(pattern, string, flags=0) pattern正则,string目标,flags控制标记

​ flags标记:re.i, re.IGNORECASE:忽略大小写

re.M, re.MULTILINE:^匹配每行开始

re.S, re.DOTALL:. 匹配所有字符

re.compile(pattern, flags=0):字符串编译成正则表达式

import re

match = re.search(r'[1-9]\d{5}','BIT 100081')
if match:
    print(match.group(0))	#match对象:输出匹配字符段group(0)


# 面向对象用法
pat = re.compile(r'[1-9]\d{5}')
rst = pat.search('BIT 100081')
# 匹配\\n: re.search('\\\\n', text)
# 匹配\c:re.search(r '\\c', text)

match对象

属性:string待匹配文本,re(pattern对象),pos搜索开始位置,endpos搜索结束位置

常用方法:**group(0)**匹配后的字符串,**start()**搜索开始位置,**end()**搜索结束位置,**span()**返回(start和end)

​ group:等价group(0),整个满足条件的字符串

​ groups:子组,索引从1开始

​ group(1):第一个子组 (子组:())

贪婪匹配:默认最长子串,加?表非贪婪

最小匹配操作符 说明
*? 0或无限次扩展
+? 前一个字符,1+
?? 前1,(0|1)
{m,n}? 前1,m-n次
实例:淘宝搜索
  1. 循环获取页面

  2. 对于每个页面,提取信息

  3. 输出

    ​ headers获取:

    ​ 1.登录淘宝,进入搜索页,F12
    ​ 2.选择Network,刷新一下,找到最上方以search?开头的文件,右键

    ​ 3.选择copy,copy as cURL(bush)

    ​ 4.在https://curl.trillworks.com/,粘贴到curl command窗口
    ​ 5.复制右侧的headers内容,以变量header保存,作为参数传给requests.get

import re
import requests

def getHTMLText(url):
    header = {
    '...'
}
    try:
        r = requests.get(url, timeout=30, headers = header)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        print('Fail')
        return ''
   
def parsePage(ilt, html):	#查看源代码,找tag
    try:
        plt = re.findall(r'"view_price":"[\d.]*"', html)
        tlt = re.findall(r'"raw_title":".*?"', html)
        for i in range(len(plt)):
            price = eval(plt[i].split(':')[1]) #去最外层引号
            title = eval(tlt[i].split(':')[1])
            ilt.append([title,price])
    except:
        print("")
   
def printGoodsList(ilt):
    tplt = '{:4}\t{:16}\t{:8}'
    print(tplt.format("序号", "名称", "价格"))
    count=0
    for g in ilt:
        count += 1
        print(tplt.format(count, g[0], g[1]))
   
def main():
    goods = "鼠标"
    depth = 2
    start_url = 'https://s.taobao.com/search?q=' + goods
    infoList = []
    for i in range(depth):
        try:
            url = start_url + '&s=' + str(44*i)
            html = getHTMLText(url)
            parsePage(infoList, html)
        except:
            continue
    printGoodsList(infoList)
    
   
if __name__ == '__main__':
    main()
    
实例:股票爬虫requests-bs4-re
  1. 名称和交易信息,保存到文件(新浪股票,百度股票)

  2. 选取原则:静态存在与HTML页面,非js代码生成,无robots限制,F12查看

  3. 设计:获取列表—逐个获取信息—存储(字典)!更改http://app.finance.ifeng.com/list/stock_cate.php?c=E48

相关标签: python 数据分析