如何在不编码和提取Python3的不编码和提取所需URL的情况下读取文件



环境: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'))

没有安装内容的计算机上,因此使用这些代码样本的里程可能会有所不同

最新更新