小白python爬虫学习3(regular expression正则表达式RE)-淘宝商品,股票实例

小白python爬虫学习3(regular expression正则表达式RE)-淘宝商品,股票实例依旧这些代码来自北理课程 之后会解释与学习相关知识 一 获取淘宝的商品与价格的代码 import requests import re def getHTMLText url try r requests get url timeout 30 r raise for status r

大家好,我是讯享网,很高兴认识大家。

依旧这些代码来自北理课程,之后会解释与学习相关知识

一:获取淘宝的商品与价格的代码:

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()

讯享网

第一段:常规操作(在上篇文章中已有介绍)

第二段:会发现有一系列乱七八糟的符号串,这是正则表达式-先学习一下正则

正则表达式是为了简洁的表达一组字符串,也可以说正则表达式是通用的字符串表达框架

举例:“PY”,“PYY”,“PYYY”,“PY....”=“PY+”:“+”表示P后面有无穷多个Y

正则表达在文本处理中比较常用

  1. 如匹配字符串的全部或部分
  2. 同时查找或替换一组字符串
  3. 表达文本类型的特征

如下常用表达式

.

操作符 说明 实例
.

表示任何单个字符

 
[] 字符集,对单个字符给出取值范围

[abc]表示a、b、c,[a-z]表示a到z单个字符

[^] 非字符集,对单个字符给出排除范围 [^abc]表示非a且非b非c的单个字符
* 前一个字符0次或无限次扩展 abc*表示ab、abc、abcc
+ 前一个字符1次或无限次扩展 abc+表示abc,abccc
? 前一个字符0次或1扩展

abc?表示abc,ab

! 左右表达式任意一个 abc|def表示abc、def

 

 

 

 

 

 

 

 

操作符 说明 实例
{m} 扩展前一个字符m次

ab{2}c表示abbc

{m,n} 扩展前一个字符m至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]  

 

 

 

 

 

 

 

按照课程先尝试一下

正则表达式 对应字符串
P(Y|YT|YTH|YTHO)?N

'PN'、'PYN'、PYTN......

PYTHON+ 'PYTHOM'、'PYTHONN'.....
PY[TH]ON 'PYTON','PYTHON'........
PY[^TH]?ON 'PYON','PYAON'.......

经典正则表达式实例

对应字符串
^[A-Za-z]+$ 由26个字母组成的字符串
^[A-Za-z0-9]+$ 由26个字母和数字组成的字符串

 

^-?\d+$ 整数形式的字符串
^[0-9]*[1-9][0-9]*$ 正整数形式的字符串
[1-9]\d{5} 中国境内邮政编码,6位
[\u4e00-\u9fa5] 匹配中文字符(以utf-8为基础)
\d{3}-\d{8}|\{4}-\d{7} 国内电话号码

\d+.\d+.\d+.\d+(不精确)

IP地址字符串形式的正则表达式
\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}(不精确)
   

正则表达式的表示类型有


讯享网

  1. raw string 类型(原生字符串类型)
  2. string 类型,更繁琐一些

两个类型的区别还是很有意思的,简单介绍下,在string中"\"用作转义符,而在正则表达式中对于有特殊意义的字符前面也要加上"\"才能匹配,如想要匹配"*"就需要"\*",这样区别就很明显了,string类型比raw string类型还要多了一次转义,比如:要匹配"\c"用string类型是这样re.search('\\\\c',text)而用原生字符串表示的话就可以这样re.search("\\c",text),为什么呢???

注意string比raw string多了一次转义,所以'\\\\c'先被string转义为'\\c'然后又在正则中转义为"\c"大致就是这样的一个过程

re库的介绍

讯享网import re

导入

re库的主要功能函数

函数 说明
re.search(pattern,string,flags=0) 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match(pattern,string ,flags=0) 从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall(pattern,string,flags=0) 搜索字符串,以列表类型返回全部能匹配的字串
re.split(pattern,string,maxsplit=0,flags=0) 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.finditer() 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
re.sub(pattern,repl,string,count=0,flags=0) 在一个字符串中替换所有匹配正则表达式的字串,返回替换后的字符串
re.compile(pattern,flags=0) 将正则字符串编译成正则表达式对象
pattern 正则表达式的字符串 string 要与正则表达式匹配的字符串 flag(正则表达式的控制标记) re.I 忽略正则表达式的大小写  
re.M ‘^’操作符能将给定字符串的每行当做匹配开始
re.S '.'能够匹配处换行外的所有字符

表格中提到返回match对象,那么这个match对象是什么呢???

Match的属性

属性 说明
.string 待匹配的文本
.re 匹配时使用的pattern对象(正则表达式)
.pos 正则表达式搜索文本的开始位置
.endpos 正则表达式搜索文本的结束位置

 

Match的方法

方法 说明
.group(0) 获得匹配后的字符串
.start() 匹配字符串在原始字符串的开始位置
.end() 匹配字符串在原始字符串的结束位置
.span() 返回(.star(),.end())

re库的俩种等价用法

  1. 一次性操作:rst=re.search(r'[1-9]\d{5}','BIT ')
  2. 编译后多次操作:pat=re.compile(r'[1-9]\d{5}')         rst=pat.search('BIT ')

问题又来了,假设现在要匹配的字符串是这样的   re.search(r'PY.*N','PYANBNCNDN')

这个时候函数该返回什么呢???事实上re库采用的是贪婪匹配就是匹配的尽量多输出最长的字串,所以返回的是PYANBNCNDN

那么有时候也会想要最短的字符串此时如何改进???

操作符 说明
*? 前一个字符0次或无限次扩展,最小匹配
+? 前一个字符1次或无限次扩展,最小匹配
?? 前一个字符0次或一次扩展,最小匹配
{m,n}?

扩展前一个字符m至n次,最小匹配

 

掌握了上面的知识,来看一下这第二段函数究竟想表达什么

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("")


        for i in range(len(plt)):
            price = eval(plt[i].split(':')[1])
            title = eval(tlt[i].split(':')[1])
            ilt.append([price , title])
    except:
        print("")

这里的len用于返回对象的长度,我感觉应该是字串的个数。eval函数在这里的作用主要还是用于去掉双引号,eval函数在这里主要是用来去掉双引号,eval函数的其他用途是什么呢?请看这篇

eval函数的作用

剩下的函数便不用在解释了,所以这个函数便是从返回的HTML页面找到名称和价格并返回列表

最后一个函数:就不介绍了,有些简单。。。

 

 

 

二:获取股票相关信息的代码,之后会一一解释作用

讯享网#CrawBaiduStocksB.py
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()

由于百度股票已经凉了,所以。。。。。。。。。。这个代码实践意义有些过小,不过没关系,它还有学习意义呀。。。。

这里最重要的还是第二个函数 def getStockList(lst, stockURL):

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

 关于BeautifulSoup类上一篇已讲过小白python爬虫学习2(初识Request,Beautifulsoup,print)在此不再赘述

关于split()[0]-----split函数默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等取分割的第一个

关于不换行的进度条 关键"\r"将光标提到第一行首位。。。。。。

OK终于写完了,以后再补充

小讯
上一篇 2025-02-13 21:19
下一篇 2025-03-25 18:02

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/124960.html