原创于2022/10/24。修改:2022/11/5。
在用Python爬网页抓取文字时有各种方法:BeautifulSoup、xpath、find_element、re正则表达式等。如何实现从一个指定的位置开始查找,需要花时间琢磨代码。我从中国银行最新汇率的网页爬汇率数据来练手,思路很简单,先找到页面中的美元,然后从美元这个位置开始找旁边的汇率数据。
各位大佬看到这里可能会说,这超级简单啊,上面的BeautifulSoup、xpath、find_element随便一个都能拿下来。别人造好的车轮都有得卖,为什么还要自己造一个?但是我的目的是不借助其它库的函数,只用Python自带的find来实现,重新造一个适合自己用的代码,如果编译成exe也可尽量缩小exe的大小。
import requests
def my_find(string,from_where,start_str,end_str):
# 参数说明:
# string:源字符串
# from_where:从哪里开始找,类型可以是字符串,也可以是整数(整数意味着具体位置)
# start_str:要找的关键词的开头
# end_str:要找的关键词的结尾
t1=string.find(from_where)+len(from_where) if type(from_where)==str else from_where
t2=string.find(start_str,t1)+len(start_str)
t3=string.find(end_str,t2)
if t1==-1 or t2==-1 or t3==-1:
return ''
else:
return string[t2:t3],t3+len(end_str) # 返回字符串以及最后一次查找的位置
url='https://www.boc.cn/sourcedb/whpj/'
headers={'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36',}
res=requests.get(url,headers=headers)
res.encoding='utf-8'
res=res.text
print('今天汇率:\n币种\t现汇买入价\t现钞买入价\t现汇卖出价\t现钞卖出价\t中行折算价\n'+'-'*85)
for i in ['美元','港币','欧元','英镑','卢布','日元']:
# 第一次找指定币种旁边的汇率数据
my_str=my_find(res,"<td>"+i+"</td>","<td>","</td>")
# 返回的结果类型是元组,元素分别是汇率数据、查找的位置
# 先输出第一个汇率数据,my_str后面要有[0]
print(i+':\t'+my_str[0],end='\t\t')
# 然后从上一次查找的位置顺着查找同一行其他四列的汇率数据
# 这时my_find函数第二个参数my_str[1]是上一次查找的位置
for j in range(4):
my_str=my_find(res,my_str[1],"<td>","</td>")
print(my_str[0],end='\t\t')
print()
上述my_find函数代码中的t1、t2、t3图解:
运行结果截图(注:下面截图是2022/11/5的汇率数据,上面截图中的汇率数据是2022/10/24):
以上是我自己造的“车轮”。下面示范一下用现成的“车轮”(比如xpath)来查找文字,首先查找汇率页面中的“美元”,定好位再顺藤摸瓜找下一级数据,代码为:
# 定位td标签内容中含有“美元”的标签
//td[contains(text(),"美元")]
# 从含有“美元”字样的下一级td标签抓取文字
//td[contains(text(),"美元")]/following-sibling::td[1]/text()
xpath需要先从lxml库引入etree:from lxml import etree。
import requests
from lxml import etree
url='https://www.boc.cn/sourcedb/whpj/'
headers={'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36',}
res=requests.get(url,headers=headers)
res.encoding='utf-8'
res=res.text
html=etree.HTML(res)
print('今天汇率:\n币种\t现汇买入价\t现钞买入价\t现汇卖出价\t现钞卖出价\t中行折算价\n'+'-'*85)
for i in ['美元','港币','欧元','英镑','卢布','日元']:
print(i+':',end='\t')
for j in range(1,6):
print(html.xpath('//td[contains(text(),"'+i+'")]/following-sibling::td['+str(j)+']/text()')[0],end='\t\t')
print()
使用xpath做匹配字符串的表达式晦涩难懂,需要多花时间理解。例一代码的my_find()是自己写的,容易理解,只是在某些复杂情况下可能不奏效。
我将以上两个例子的代码分别编译成exe文件(在虚拟环境中编译,以求最小的exe体积),exe体积分别是:
例一(自编函数): 7.03MB
例二(引入lxml库): 9.43MB