环境:python3。
有很多文件,有些文件用GBK编码,另一些则用UTF-8编码。我想用正则表达式提取所有JPG
用于用GBK编码的s.html。
tree = open("/tmp/s.html","r").read()
unicodedecodeerror:'utf-8'编解码器无法在位置135中解码字节0xb4:无效启动字节
tree = open("/tmp/s.html","r",encoding="gbk").read()
pat = "http://.+.jpg"
result = re.findall(pat,tree)
print(result)
['http://somesite/2017/06/0_56.jpg']
用指定的编码打开所有文件是一项巨大的工作,我想要一种在所有文件中提取JPG URL的聪明方法。
我也有类似的问题,我如何解决此问题如下。
在get_file_encoding(filename)
中,我首先检查文件中是否有BOM(字节订单标记(,如果是,请从BOM中获取编码。来自功能:get_file_bom_encoding(filename)
如果没有返回值,我将从该函数中获取列表: get_all_file_encodings(filename)
此列表将具有可以打开文件的所有编码。为了我这样做的目的,我只需要一个,而我不在乎其余的,所以我只选择列表 file_encoding = str(encoding_list[0][0])
的第一个值
这显然不是准确的100%,但至少它将为您提供从BOM的正确编码,或者它会为您提供可以打开文件的编码列表。或者,如果您这样做相同,它将为您提供一个(第一个值(编码该文件的情况。
在这里代码:
# -*- coding: utf-8 -*-
import codecs
def get_file_bom_encoding(filename):
with open (filename, 'rb') as openfileobject:
line = str(openfileobject.readline())
if line[2:14] == str(codecs.BOM_UTF8).split("'")[1]: return 'utf_8'
if line[2:10] == str(codecs.BOM_UTF16_BE).split("'")[1]: return 'utf_16'
if line[2:10] == str(codecs.BOM_UTF16_LE).split("'")[1]: return 'utf_16'
if line[2:18] == str(codecs.BOM_UTF32_BE).split("'")[1]: return 'utf_32'
if line[2:18] == str(codecs.BOM_UTF32_LE).split("'")[1]: return 'utf_32'
return ''
def get_all_file_encodings(filename):
encoding_list = []
encodings = ('utf_8', 'utf_16', 'utf_16_le', 'utf_16_be',
'utf_32', 'utf_32_be', 'utf_32_le',
'cp850' , 'cp437', 'cp852', 'cp1252', 'cp1250' , 'ascii',
'utf_8_sig', 'big5', 'big5hkscs', 'cp037', 'cp424', 'cp500',
'cp720', 'cp737', 'cp775', 'cp855', 'cp856', 'cp857',
'cp858', 'cp860', 'cp861', 'cp862', 'cp863', 'cp864',
'cp865', 'cp866', 'cp869', 'cp874', 'cp875', 'cp932',
'cp949', 'cp950', 'cp1006', 'cp1026', 'cp1140', 'cp1251',
'cp1253', 'cp1254', 'cp1255', 'cp1256', 'cp1257',
'cp1258', 'euc_jp', 'euc_jis_2004', 'euc_jisx0213',
'euc_kr', 'gb2312', 'gbk', 'gb18030', 'hz', 'iso2022_jp',
'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_2004',
'iso2022_jp_3', 'iso2022_jp_ext', 'iso2022_kr', 'latin_1',
'iso8859_2', 'iso8859_3', 'iso8859_4', 'iso8859_5',
'iso8859_6', 'iso8859_7', 'iso8859_8', 'iso8859_9',
'iso8859_10', 'iso8859_13', 'iso8859_14', 'iso8859_15',
'iso8859_16', 'johab', 'koi8_r', 'koi8_u', 'mac_cyrillic',
'mac_greek', 'mac_iceland', 'mac_latin2', 'mac_roman',
'mac_turkish', 'ptcp154', 'shift_jis', 'shift_jis_2004',
'shift_jisx0213'
)
for e in encodings:
try:
fh = codecs.open(filename, 'r', encoding=e)
fh.readlines()
except UnicodeDecodeError:
fh.close()
except UnicodeError:
fh.close()
else:
encoding_list.append([e])
fh.close()
continue
return encoding_list
def get_file_encoding(filename):
file_encoding = get_file_bom_encoding(filename)
if file_encoding != '':
return file_encoding
encoding_list = get_all_file_encodings(filename)
file_encoding = str(encoding_list[0][0])
if file_encoding[-3:] == '_be' or file_encoding[-3:] == '_le':
file_encoding = file_encoding[:-3]
return file_encoding
def main():
print('This Python script is only for import functionality, it does not run interactively')
if __name__ == '__main__':
main()
我敢肯定有一些模块/软件包可以更准确地执行此操作,但这是使用标准软件包(这是我有的另一个要求(
这确实意味着您要多次读取文件,这不是一种快速的做事方式。您也许可以使用它来满足自己的特定问题,甚至可以对此进行改进,尤其是"多次阅读"。是您可以查看的东西,并在找到一个编码后立即打开文件。
如果它们混合编码,您可以尝试一个编码并落回另一个:
# first open as binary
with open(..., 'rb') as f:
f_contents = f.read()
try:
contents = f_contents.decode('UTF-8')
except UnicodeDecodeError:
contents = f_contents.decode('gbk')
...
如果它们是HTML文件,您也可以找到编码标签,或用二进制正则二进制搜索它们:
contents = open(..., 'rb').read()
regex = re.compile(b'http://.+.jpg')
result = regex.findall(contents)
# now you'll probably want to `.decode()` each of the urls, but you should be able to do that pretty trivially with even the `ASCII` codec
尽管我已经想到了,但您可能真的不想使用正则链接来捕获链接,因为您必须与HTML实体打交道(&
(,并且可以使用Pyquery
这是使用Pyquery
的快速示例contents = open(..., 'rb').read()
pq = pyquery.PyQuery(contents)
images = pq.find('img')
for img in images:
img = pyquery.PyQuery(img)
if img.attr('src').endswith('.jpg')
print(img.attr('src'))
没有安装内容的计算机上,因此使用这些代码样本的里程可能会有所不同