Python网络爬虫与信息提取——网络爬虫规则(Re篇)

第四章 网络爬虫之规则(Re正则表达式篇)

● Re(正则表达式)库入门

  • 正则表达式简介
    1、RE(regular expression,regex,正则表达式)是用来简洁表达一组字符串的表达式。
    2、RE库理解;1)通用的字符串表达框架;
           2)简洁表达一组字符串的表达式;
           3)针对字符串表达“简洁”和“特征”思想的工具;
           4)判断某字符串的特征归属。
    3、正则表达式常用于文本处理:
      1)表达文本类型的特征(病毒、人侵等);
      2)同时查找或替换一组字符串;
      3)冷匹配字符串的全部或部分。
    4、正则表达式的使用——编译:将符合正则表达式语法的字符串转换成正则表
    达式特征。
  • 正则表达式语法
    1、正则表达式语法由字符和操作符构成。例:P(Y|YT|YTH|YTHO)?N
    2、正则表达式常用操作符
    操作符说明实例
    .表示任何单个字符
    [ ]字符集,对单个字符给出取值范围[abc]表示a、b、c,[a-2]表示a到z单个字符
    [^]非字符集,对单个字符给出排除范围[^abc]表示非a或b或c的单个字符
    *前一个字符0次或无限次扩展abc*表示ab、abc、abcc、abccc等
    +前一个字符1次或无限次扩展abc+表示abc、abcc、abccc等
    ?前一个字符0次或1次扩展abc?表示ab、abc
    |左右表达式任意一个abc|def表示abc、def
    {m}扩展前一个字符m次ab{2)c表示abbc
    {m,n}扩展前一个字符m至n次(含n)ab{1,2}c表示abc、abbc
    ^匹配字符串开头^abc表示abc且在一个字符串的开头
    $匹配字符串结尾abc$表示abc且在一个字符串的结尾
    ()分组标记,内部只能使用|操作符(abc)表示abc,(abc|def)表示abc、def
    \d数字,等价于[0-9]
    \w单词字符,等价于[A-Za-z0-9_]
      实例:
         实例
        精确写法:IP地址字符串形式的正则表达式(IP地址分4段,每段0-255)
        IP匹配
  • Re库的基本使用
    1、Re库介绍:Re库是Python的标准库,主要用于字符串匹配。
           调用方式: import re
    2、正则表达式的表示类型
    1) raw string类型(原生字符串类型,不包含转义符的字符串)—re库采用raw string类型表示正则表达式,表示为:r‘text’
    2)string类型—使用转移字符\表示\,更繁琐
    3、Re库主要功能函数
        Re库主要功能函数
      1)re.search()方法
       使用格式:re.search(pattern, string, flags=0)
               -pattern:正则表达式的字符串或原生字符串表示
               -string:待匹配字符串
               -flags:正则表达式使用时的控制标记
             flags:正则表达式使用时的控制标记
             flags控制标记
    >>> import re
    >>> match = re.search(r'[1-9]\d{5}','BIT 100081')
    >>> if match:
    ...     print (match.group(0))
    ...
    100081
    

  2)re.match()方法
   使用格式:re.match(pattern, string, flags=0)
           -pattern:正则表达式的字符串或原生字符串表示
           -string:待匹配字符串
           -flags:正则表达式使用时的控制标记

>>> import re
>>> match = re.match(r'[1-9]\d{5}','BIT 100081')
>>> if match:
...     print(match.group(0))
...
>>> match.group(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> match = re.match(r'[1-9]\d{5}','100081 BIT')
>>> if match:
...     print(match.group(0))
...
100081

   注:空变量没有group(),使用正则表达式匹配结果,先用if判断结果是否为空。
  3)re.findall()方法
   使用格式:re.findall(pattern, string, flags=0)
           -pattern:正则表达式的字符串或原生字符串表示
           -string:待匹配字符串
           -flags:正则表达式使用时的控制标记

>>> import re
>>> ls = re.findall(r'[1-9]\d{5}','BIT100081 TSU100084')
>>> ls
['100081', '100084']

  4)re.split()方法
   使用格式:re.split(pattern, string,maxsplit=0, flags=0)
           -pattern:正则表达式的字符串或原生字符串表示
           -string:待匹配字符串
           -maxsplit:最大分割数,剩余部分作为最后一个元素输出
           -flags:正则表达式使用时的控制标记

>>> import re
>>> re.split(r'[1-9]\d{5}','BIT100081 TSU100084')
['BIT', ' TSU', '']
>>> re.split(r'[1-9]\d{5}','BIT100081 TSU100084',maxsplit=1)
['BIT', ' TSU100084']

  5)re.finditer()方法
   使用格式:re.finditer(pattern, string, flags=0)
           -pattern:正则表达式的字符串或原生字符串表示
           -string:待匹配字符串
           -flags:正则表达式使用时的控制标记

>>> import re
>>> for match in re.finditer(r'[1-9]\d{5}','BIT100081 TSU100084'):
...     if match:
...             print(match.group(0))
...
100081
100084

  6)re.sub()方法
   使用格式:re.sub(pattern,repl, string,count=0, flags=0)
           -pattern:正则表达式的字符串或原生字符串表示
           -repl:替换匹配字符串的字符串
           -string:待匹配字符串
           -count:匹配的最大替换次数
           -flags:正则表达式使用时的控制标记

>>> import re
>>> re.sub(r'[1-9]\d{5}',':zipcode','BIT100081 TSU100084')
'BIT:zipcode TSU:zipcode'

4、Re库的等价用法
  1)函数式用法:一次性操作
    例:res = re.search(r’[1-9]\d{5}’,‘BIT 100081’)
  2)面向对象用法:编译后的多次操作
    例:match = re.compile(r’[1-9]\d{5}’)
      res = match.search(‘BIT 100081’)
    re.compile(pattern, flags=0)
    作用:将正则表达式的字符串形式编译成正则表达式对象
           -pattern:正则表达式的字符串或原生字符串表示
           -flags:正则表达式使用时的控制标记

  • Re库的match对象
    1、match对象属性:
    match对象属性
    2、match对象的方法:
    match对象的方法
>>> import re
>>> match = re.search(r'[1-9]\d{5}','BIT100081 TSU100084')
>>> match.string
'BIT100081 TSU100084'
>>> match.re
<_sre.SRE_Pattern object at 0x028092C0>
>>> match.pos
0
>>> match.endpos
19
>>> match.group(0)
'100081'
>>> match.start()
3
>>> match.end()
9
>>> match.span()
(3, 9)
  • Re库的的贪婪匹配与最小匹配
    1、贪婪匹配:Re库默认釆用贪娈匹配,即输出匹配最长的子串。
>>> match = re.search(r'PY.*N','PYANBNCNDN')
>>> match.group(0)
'PYANBNCNDN'

2、最小匹配:输出最短的字符串
  最小匹配操作符
      在这里插入图片描述
● Re(正则表达式)库实例

  • 淘宝商品比价定向爬虫
    1、功能描述
      目标:获取淘宝搜索页面的信息,提取其中的商品名称和价格。
      理解:淘宝的搜索接口、翻页的处理
      技术路线::requests-re
    2、规律查找:搜索书包
          淘宝书包页面
    3、定向爬虫的可行性—robot.txt
    4、程序结构设计
      步骤1:提交商品搜索请求,循环获取页面。
      步骤2:对于每个页面,提取商品名称和价格信息。
      步骤3:将信息输出到屏幕上。
    5、程序设计(仅供参考):
import requests
import re

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 parsePage(ilt, html):
    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([price , title])
    except:
        print("")
 
def printGoodsList(ilt):
    tplt = "{:4}\t{:8}\t{:16}"
    print(tplt.format("序号", "价格", "商品名称"))
    count = 0
    for g in ilt:
        count = count + 1
        print(tplt.format(count, g[0], g[1]))
         
def main():
    goods = '书包'
    depth = 3
    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)
     
main()
  • 股票数据定向爬虫
    1、功能描述
      目标:获取上交所和深交所所有股票的名称和交易信息
      输出:保存到文件中
      技术路线:requests-bs4-re
    2、候选数据网站的选择
      选取原则:股票信息静态存在于HTML页面中,非js代码生成,没有 Robots协议限制。
      选取方法:浏览器F12,源代码查看等。
      选取心态:不要纠结于某个网站,多找信息源尝试。
    3、程序的结构设计
      步骤1:从东方财富网获取股票列表
      步骤2:根据股票列表逐个到百度股票获取个股信息
      步骤3:将结果存储到文件
    4、程序设计(仅供参考):
import requests
from bs4 import BeautifulSoup
import traceback
import re
 
def getHTMLText(url, code="utf-8"):
    try:
        r = requests.get(url)
        r.raise_for_status()
        r.encoding = code
        return r.text
    except:
        return ""
 
def getStockList(lst, stockURL):
    html = getHTMLText(stockURL, "GB2312")
    soup = BeautifulSoup(html, 'html.parser') 
    a = soup.find_all('a')
    for i in a:
        try:
            href = i.attrs['href']
            lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
        except:
            continue
 
def getStockInfo(lst, stockURL, fpath):
    count = 0
    for stock in lst:
        url = stockURL + stock + ".html"
        html = getHTMLText(url)
        try:
            if html=="":
                continue
            infoDict = {}
            soup = BeautifulSoup(html, 'html.parser')
            stockInfo = soup.find('div',attrs={'class':'stock-bets'})
 
            name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
            infoDict.update({'股票名称': name.text.split()[0]})
             
            keyList = stockInfo.find_all('dt')
            valueList = stockInfo.find_all('dd')
            for i in range(len(keyList)):
                key = keyList[i].text
                val = valueList[i].text
                infoDict[key] = val
             
            with open(fpath, 'a', encoding='utf-8') as f:
                f.write( str(infoDict) + '\n' )
                count = count + 1
                print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
        except:
            count = count + 1
            print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
            continue
 
def main():
    stock_list_url = 'https://quote.eastmoney.com/stocklist.html'
    stock_info_url = 'https://gupiao.baidu.com/stock/'
    output_file = 'D:/BaiduStockInfo.txt'
    slist=[]
    getStockList(slist, stock_list_url)
    getStockInfo(slist, stock_info_url, output_file)
 
main()

5、程序优化之处—提高用户体验
  1)速度提高:编码识别的优化
  2)体验提高:增加动态进度显示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值