这样写
s = f.readline()
for i in s:
...
否则readline读取了很多次
对列表中保存的数据进行打印,并保存到文本文档中。这个时候遇到了本次实验最大问题:输出无法对齐。
如下图,在使用format尝试对齐时,发现中英文字符混杂的书名和作者会导致无法对齐。
(如果只包含中文,输出还是可以对齐的,把空格改为全角空格即可)
修改为全角空格填充,依然没用。
既然自动填充空格无效,我们尝试编写函数手动填充空格。查阅资料可知,中文字符在UTF8编码下占据三个字节,英文字符在UTF8编码下占据一个字节。因此我们在打印一个字符串之前,可以通过遍历字符串,计算其中中文字符和英文字符各自的数目。
(gbk编码下中文字符占据两个字节)
在文本编辑器中,中文字符的宽度正好是英文字符的两倍,因此我们通过公式
“width * 2 - sigle - double * 2”就可以计算出应该填充空格的数目。(width是为字符串设定的占用长度)
格式函数代码如下图。再次进行输出,依然无法对齐。
仔细查看输出结果,发觉在python的打印中,中文字符的宽度并不等于英文字符的两倍!
而是8:5的关系!!
(笔者有种想杀人的冲动!!!)
于是把原公式中的2改成1.6,但显然当计算得到的空格数目不是整数的,输出距离还是不正确。
我又想到可以用看不到的中文字符(灵感来源于王者荣耀重复名)对原字符串进行填充,使其中的中文字符数是5的倍数。在查阅资料后,找到了全角空格(全角空格占据的宽度等于中文字符宽度)。
因此my_format函数可以改为:
def my_format(str, width, align):#定义函数接受三个参数:要输出的字符串(str)、总占用宽度(int)、对齐方式(str:l、r对应左右)
sigle = 0
double = 0
longkong = 0
sep=' '#定义占位符
long_sep = ' '
for i in str:#统计单字宽和1.6字宽的数目
if len(i.encode('UTF-8')) == 1 or len(i.encode('UTF-8')) == 2:
sigle += 1
elif len(i.encode('UTF-8')) == 3:
double += 1
if double % 5 != 0:
longkong = (5 - double % 5)
double += longkong
if align == 'l':
return str + long_sep * longkong + int(width * 2 - sigle - double * 1.6) * sep
elif align == 'r':
return long_sep * longkong + int(width * 2 - sigle - double * 1.6) * sep + str
另外字符‘·’的encode编码是2个字符,但其字符宽度是一个英文字符,因此在遍历时单独列出。
最后输出结果,完美对齐:
另外,由于在一半的文本编辑器如记事本中,中文字符的宽度依然是英文字符的2倍,所以如果输出到文本文件中时,需要修改my_format中的参数。
完整代码
import requests
from bs4 import BeautifulSoup
import re
def getHTMLText(url):
try:
r = requests.get(url, timeout=100)
r.raise_for_status()
r.encoding = 'GBK'
#r.encoding = 'UTF-8'
return r.text
except:
return ""
def parsePage(ilt, html):
try:
soup = BeautifulSoup(html, 'html.parser')
'''
f = open("ceshi.txt", 'w', encoding="UTF-8")
f.write(str(soup))
f.close()
'''
names = soup.find_all('div', attrs = {'class': 'name'})
writers = soup.find_all('div', attrs={'class': 'publisher_info'})
price_ns = soup.find_all('span', 'price_n')
price_rs = soup.find_all('span', 'price_r')
for i in range(len(names)):
publisher = writers[2*i].text.split('(')[0].split(' ')[0].split(',')[0].split(',')[0].replace('?','·')
title = names[i].text.split('(')[0].split('(')[0].split(' ')[0].split('(')[0].replace('——','--')
price_n = price_ns[i].string
price_r = price_rs[i].string
#print(price_n, price_r)
ilt.append([publisher, title, price_n, price_r])
except:
print("")
def printGoodsList(ilt):
print(my_format('序号', 8, 'l') + my_format('书名', 25, 'l') +\
my_format('作者', 15, 'l') + my_format('当前价格', 8, 'l') + my_format('定价', 8, 'l'))
count = 0
for g in ilt:
count = count + 1
print(my_format(str(count), 8, 'l') + my_format(g[1], 25, 'l') + \
my_format(g[0], 15, 'l') + my_format(g[2], 8, 'l') + my_format(g[3], 8, 'l'))
def my_format(str, width, align):#定义函数接受三个参数:要输出的字符串(str)、总占用宽度(int)、对齐方式(str:l、r对应左右)
sigle = 0
double = 0
longkong = 0
sep=' '#定义占位符
long_sep = ' '
for i in str:#统计单字宽和1.6字宽的数目
if len(i.encode('UTF-8')) == 1 or len(i.encode('UTF-8')) == 2:
sigle += 1
elif len(i.encode('UTF-8')) == 3:
double += 1
if double % 5 != 0:
longkong = (5 - double % 5)
double += longkong
if align == 'l':
return str + long_sep * longkong + int(width * 2 - sigle - double * 1.6) * sep
elif align == 'r':
return long_sep * longkong + int(width * 2 - sigle - double * 1.6) * sep + str
def main():
kind = '01.03.52.00.00.00'#排行榜书的类别,这个种类是影视小说
time = '-year-2020-0-1'#2020年整年的排行榜
depth = 10#页数
start_url = 'http://bang.dangdang.com/books/bestsellers/' + kind + time + '-'
infoList = []
for i in range(depth):
try:
url = start_url + str(i+1)
html = getHTMLText(url)
parsePage(infoList, html)
except:
continue
printGoodsList(infoList)
main()
我很抱歉,但是您的问题不能为空。请提供具体的问题以便我可以提供帮助。