导学
1 Re(正则表达式)库入门
1.1 正则表达式的概念
全部列出来太繁琐,所以使用正则表达式
能将一组字符串表达出来
例1:
例2:
编译后的特征与一组字符串是对应的
编译之前的正则表达式只是一个符合正大表达式语法的单一字符串
1.2 正则表达式语法
“.”: 字符表上出现的任一个字符
第一个:不考虑每一段的取值范围和空间,只考虑它们之间的“.”来分割
第二个:出现的每一个字符串都是0个或1个或2个或3个
上面2个都不够精确
1.3 Re库的基本使用
1.3.1 正则表达式的表示类型——原生字符串类型
原生字符串中的’'不被表示为转义符
所以:
1.3.2 Re库主要功能函数
re.search():在字符串中搜索跟正则表达式一样的地方
re.match():只在给定的位置起匹配
re.findall():在字符串中发现所有与正则表达式相同的字符串的字串
re.search()
在正则表达式中’.‘匹配除’\n’外的任意字符
例:中国邮政编码,匹配“BIT 10081”
话说,写’BIT’有什么用,从re.match()穿越回来,这个’BIT’没有什么具体的含义,只是为了说明search不一定从头开始匹配
re.match()
发现没有匹配到任何结果
因为match从头开始匹配,所以不会匹配到’BIT 100081’
如果不判断是否匹配到,就会报错
re.findall()
re.split()
上面第2个加了maxsplit=1说明只匹配1次
re.finditer()
能够迭代返回每一次的结果,并对每次结果单独处理
re.compiler()
1.4 Re库的match对象
1.4.1 Match对象的属性
1.4.2 Match对象的方法
输出的是带有compile标识的,这说明,只有经过compile的才会是正则表达式
搜索的开始位置和结束位置
match返回的是第一次的匹配结果,如果要返回每一次的,就要用finditer()
匹配字符串的开始位置和终结位置
这2个位置的二元关系
1.5 Re库的贪婪匹配和最小匹配
PY.*N:以PY开头,以N结尾,中间是任意字符的字符串
1.6 总结
实例2 “淘宝商品比价定向爬虫”(requests+re)
1 “淘宝商品比价定向爬虫”实例介绍
本例并不对淘宝的服务器进行骚扰
2 “淘宝商品比价定向爬虫”实例编写
整体架构
depth=2:爬取2页
try:
…
except:
continue
爬取某页出错后继续爬取下一页
getHTMLText()
parsePage()
因为淘宝的价格等采用的是脚本语言的体现,只用搜索就可以办到,所以不必使用bs,这里只是用了正则
不过现在在淘宝搜东西会跳出来登陆界面,这个爬虫可能不太适用于现在了
视频里的淘宝源代码
它的价格在:
- “view_price”:139.9
它的名字在: - “raw_Title”:xxxxx
第一个斜杠是转义
表示的正则表达式:“view_price”:"[\d.]* "
eval():去掉双引号
取":"后面的
printGoodsList()
表示输出第一个元素长度为4,第二个元素长度为8,第三个元素长度为16
3 总结
源代码
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()
好像不太行了,什么也没爬到
实例3 “股票数据定向爬虫”(requests+bs4+re)
1 “股票数据定向爬虫”实例介绍
查看源代码可知,百度股票更合适
但是百度股票不能在一页内找到好多个股票的信息
因此,打开东方财富网
参照页面的存储方式,对每一个信息源和信息值做相关的标定,可以利用键值对,字典类型是维护键值对的数据类型来保存各股的信息,然后再用字典把所有股的信息整合在一起
2 “股票数据定向爬虫”实例编写
为调试方便,使用traceback库
整体框架
getStockList():获得股票的列表
getStockInfo():获得单个股票的信息
getHTMLText()
getStockList()
东方财富网源代码:
都保存在中,只要解析出来,就会有股票的代码(是href的后几个数字)
使用正则表达式,但不是所有的里的href都会符合条件,所以可以使用try…except
正则表达式是深圳或上海的股票代码,以s开头,之后接h或z,然后是6个数字
getStockInfo()
百度股票那个网源代码
首先要先向各股发送请求
使用try…except来保证返回的页面是否正常
所有股票信息封装在
股票名称在class=‘bets-name’
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b718cf2dc49cfcb37930e77cdb23a713.png)
使用split函数来获得股票对应名称的完整部分,因为某些名称的后面还关联了其他的标识符,使用空格将其分开后取分出来的第0部分
然后,所有的股票的信息在
-
key
- value
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ecf7e05e3bab7615b37ff2265f172a35.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d3c2717b54f3dd03a45454e1a41bdbea.png)
完整代码
import requests
from bs4 import BeautifulSoup
import traceback
import re
def getHTMLText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def getStockList(lst, stockURL):
html = getHTMLText(stockURL)
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):
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' )
except:
traceback.print_exc()
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()
这个也不太行,网站改版了,爬不出来,与时俱进的重要性
3 “股票数据定向爬虫”实例优化
提高用户体验,但是只要是用requests和bs4就不会提高速度
3.1 速度提高:编码识别的优化
手工获得编码方式
修改为:
东方财富网的编码是’GB2312’
百度股票采用’utf-8’,不修改
3.2 体验提高:增加动态进度提示
爬取页面很多,动态显示进度,增加动态显示不换行的进度条
- 增加1个count变量
- 不换行,使用转义符’\r’,能将我们打印的字符串的最后的光标提到当前行的头部,则下一次打印时会覆盖前一次的
'\r’在idle是被禁掉的,所以使用命令行