【问题标题】:Line Breaks Prevent BeautifulSoup from Extracting Data换行符阻止 BeautifulSoup 提取数据
【发布时间】:2016-11-05 02:56:03
【问题描述】:

我的脚本通过 imaplib 从电子邮件收件箱中获取 HTML 代码,将其传递给 BeautifulSoup 并尝试提取其中的所有 hrefs。

rv, data = M.SEARCH(None, '(FROM "foo@bar.com")')
if rv == 'OK':
    for num in data[0].split():
        typ, data = M.fetch(num, '(RFC822)')
        html = data[0][1]

        soup = BeautifulSoup(html, 'lxml')
        for a in soup.find_all('a', href=True):
            print a['href']

但是,html 变量包含的 HTML 代码每 N 个字符都有一个新行,从而阻止 BeautifulSoup 准确返回 href,尤其是已被新行分割的长代码。

到处都有=0D3D这样的奇怪字符。

messages, <a=0D
href=3D"http://links.google.com/wf/click?upn=3DOGGGYNMPA980E3DmngbHusD=
Uo-2BK17XLM3ogFJfQXXXfMWZLdsQSSVv33HbPoHPXGcH8tSf9ZFFU5i-2FrV4O6ISlpDCIVaN5=
83xr1CGoa5yxZimagE5JiSUAhbZH8P7WiNvf35BsXrCxmrmRLMGB-2BJAQ-3D-3D_IcMuwcQVVt=
a699aeVjRRVxwBCNHkXaWO-2FyIlAqZ7CPsryDB24UVYZbMIvGLJb13chayC-2FLeucv-2FTrko=
7LaiaWHkzy85DWXrK1olI1SEJZs-2BMCAWfoVfloGJivlLSH0GQk0XeVT0j383tZrsymuWLF0S2=
q5j3LR91e76dRXQe7p8t5CgrBe-2FqGk6bmURG9XCNw3dwpHnymaR-2FggHQx6GnbbueF7PVp2H=
-2BGoHUEkMOSXJ8FfSgQIiGICvxz1zcBJPw-2FRoE3YDl-2By8XETkXjVaNchNA1ZN8FDCD5VUf=
V9oUOnavAirXX-2FEw1THfSpV4VYDX">unsubscribe</a></td>=0D
                </tr>=0D
                <tr>=0D
                    <td height=3D"12"></td>=0D
                </tr>=0D

我们可以做些什么来解决这个问题?

【问题讨论】:

  • 您可以尝试使用正则表达式提取hrefs,而不依赖于BeautifulSoup

标签: python html python-2.7 beautifulsoup imaplib


【解决方案1】:

您可以使用quopri 来解码Quoted-printable 数据:

Quoted-Printable 或 QP 编码是一种使用可打印 ASCII 字符(字母数字和等号“=”)通过 7 位数据路径或通常通过不是 8 位干净的介质。1 它被定义为用于电子邮件的 MIME 内容传输编码。

QP 通过使用等号“=”作为转义字符来工作。它还将行长度限制为 76,因为某些软件对行长度有限制。

html = """<a=0D
href=3D"http://links.google.com/wf/click?upn=3DOGGGYNMPA980E3DmngbHusD=
Uo-2BK17XLM3ogFJfQXXXfMWZLdsQSSVv33HbPoHPXGcH8tSf9ZFFU5i-2FrV4O6ISlpDCIVaN5=
83xr1CGoa5yxZimagE5JiSUAhbZH8P7WiNvf35BsXrCxmrmRLMGB-2BJAQ-3D-3D_IcMuwcQVVt=
a699aeVjRRVxwBCNHkXaWO-2FyIlAqZ7CPsryDB24UVYZbMIvGLJb13chayC-2FLeucv-2FTrko=
7LaiaWHkzy85DWXrK1olI1SEJZs-2BMCAWfoVfloGJivlLSH0GQk0XeVT0j383tZrsymuWLF0S2=
q5j3LR91e76dRXQe7p8t5CgrBe-2FqGk6bmURG9XCNw3dwpHnymaR-2FggHQx6GnbbueF7PVp2H=
-2BGoHUEkMOSXJ8FfSgQIiGICvxz1zcBJPw-2FRoE3YDl-2By8XETkXjVaNchNA1ZN8FDCD5VUf=
V9oUOnavAirXX-2FEw1THfSpV4VYDX">unsubscribe</a></td>=0D
                </tr>=0D
                <tr>=0D
                    <td height=3D"12"></td>=0D
                </tr>=0D"""


from bs4 import BeautifulSoup
import quopri

soup = BeautifulSoup(quopri.decodestring(html), "lxml")
print(soup)
print(soup.select_one("a")["href"])

将输出:

<html><body><a href="http://links.google.com/wf/click?upn=OGGGYNMPA980E3DmngbHusDUo-2BK17XLM3ogFJfQXXXfMWZLdsQSSVv33HbPoHPXGcH8tSf9ZFFU5i-2FrV4O6ISlpDCIVaN583xr1CGoa5yxZimagE5JiSUAhbZH8P7WiNvf35BsXrCxmrmRLMGB-2BJAQ-3D-3D_IcMuwcQVVta699aeVjRRVxwBCNHkXaWO-2FyIlAqZ7CPsryDB24UVYZbMIvGLJb13chayC-2FLeucv-2FTrko7LaiaWHkzy85DWXrK1olI1SEJZs-2BMCAWfoVfloGJivlLSH0GQk0XeVT0j383tZrsymuWLF0S2q5j3LR91e76dRXQe7p8t5CgrBe-2FqGk6bmURG9XCNw3dwpHnymaR-2FggHQx6GnbbueF7PVp2H-2BGoHUEkMOSXJ8FfSgQIiGICvxz1zcBJPw-2FRoE3YDl-2By8XETkXjVaNchNA1ZN8FDCD5VUfV9oUOnavAirXX-2FEw1THfSpV4VYDX">unsubscribe</a>
<tr>
<td height="12"></td>
</tr> </body></html>
http://links.google.com/wf/click?upn=OGGGYNMPA980E3DmngbHusDUo-2BK17XLM3ogFJfQXXXfMWZLdsQSSVv33HbPoHPXGcH8tSf9ZFFU5i-2FrV4O6ISlpDCIVaN583xr1CGoa5yxZimagE5JiSUAhbZH8P7WiNvf35BsXrCxmrmRLMGB-2BJAQ-3D-3D_IcMuwcQVVta699aeVjRRVxwBCNHkXaWO-2FyIlAqZ7CPsryDB24UVYZbMIvGLJb13chayC-2FLeucv-2FTrko7LaiaWHkzy85DWXrK1olI1SEJZs-2BMCAWfoVfloGJivlLSH0GQk0XeVT0j383tZrsymuWLF0S2q5j3LR91e76dRXQe7p8t5CgrBe-2FqGk6bmURG9XCNw3dwpHnymaR-2FggHQx6GnbbueF7PVp2H-2BGoHUEkMOSXJ8FfSgQIiGICvxz1zcBJPw-2FRoE3YDl-2By8XETkXjVaNchNA1ZN8FDCD5VUfV9oUOnavAirXX-2FEw1THfSpV4VYDX

如果您打印十六进制字符 3D0D,您会发现这一切都有意义:

In [4]: print("\x3D")
=

In [5]: print("\x0D")


In [6]: 

【讨论】:

  • 所以 这就是为什么 Linux 上的 base64 实用程序会在第 76 个字符之后换行,除非您添加 --wrap=0-w 0!谢谢:)
猜你喜欢
  • 1970-01-01
  • 2014-08-05
  • 2019-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 1970-01-01
相关资源
最近更新 更多