使用Beautiful Soup抓取:为什么get_text方法无法返回该元素的文本?

3 投票
2 回答
2560 浏览
提问于 2025-04-18 05:08

最近我在做一个Python项目,主要是从一些网站上抓取代理服务器的信息。遇到的问题是,当我试图从一个知名的代理网站抓取数据时,使用Beautiful Soup这个工具找IP地址时,它的表现和我预期的不太一样。我想要抓取每个代理的IP地址,但当我在合适的元素上使用Beautiful Soup的.get_text()方法时,得到的结果却是这样。

...

.UbZT{display:none}
.f5fa{display:inline}
.Glj2{display:none}
.cUce{display:inline}
.zjUZ{display:none}
.GzLS{display:inline}
98120169.117.186373161218218.83839393101138154165203242 

...

这是我想要解析的元素(包含IP的td标签):

<td><span><style>
.lLXJ{display:none}
.qRCB{display:inline}
.qC69{display:none}
.V0zO{display:inline}
</style><span style="display: inline">190</span><span class="V0zO">.</span><span 
style="display:none">2</span><div style="display:none">20</div><span 
style="display:none">51</span><span style="display:none">56</span><div 
style="display:none">56</div><span style="display:none">61</span><span 
class="lLXJ">61</span><div style="display:none">61</div><span 
class="qC69">110</span><div 
style="display:none">110</div><span style="display:none">135</span><div 
style="display:none">135</div><span class="V0zO">221</span><span 
style="display:none">234</span><div style="display:none">234</div><span class="147">.
</span><span style="display: inline">29</span><div style="display:none">44</div><span 
style="display:none">228</span><span></span><span class="qC69">248</span>.<span 
style="display:none">7</span><span></span><span style="display:none">44</span><span 
class="qC69">44</span><span class="qC69">80</span><span></span><span 
style="display:none">85</span><span class="lLXJ">85</span><div 
style="display:none">85</div><span class="qC69">100</span><div 
style="display:none">100</div><span></span><span class="qC69">130</span><div 
style="display:none">130</div><div style="display:none">168</div>212<span 
style="display:none">230</span><span class="qC69">230</span><div 
style="display:none">230</div></span></td>  

这个元素的实际文本就是代理的IP地址。

这是我代码的一部分:

# Hide My Ass
pages = ['https://www.hidemyass.com/proxy-list']

for page in pages:
    hidemyass = Soup(requests.get(page).text)
    rows = hidemyass.find_all(lambda tag:tag.name=='tr' and tag.has_attr('class'))
    for row in rows:
        fields = row.find_all('td')
        # get ip, port, and protocol for proxy
        ip = fields[1].get_text()            # <-- Here's the above td element
        port = fields[2].get_text()
        protocol = fields[6].get_text().lower()
        # store proxy in database
        db.add_proxy({'ip':ip,'port':port,'protocol':protocol})
        num_found += 1

有没有什么正确的方法来解析这个元素,这样输出的结果就不会像这样混乱呢?我本以为Beautiful Soup的.get_text()方法会返回网站上可见的文本,但看来并不是这样。感谢任何帮助或建议。

2 个回答

0

我之前用这段代码来解析Hidemyass.com的网站内容(这段代码是用Perl写的,使用正则表达式来解析HTML其实不是个好方法):

sub find_ip {

  my ($html) = @_;
  my $ip;

  my ($style_section) = $html =~ m{<style>(.+?)</style>};

  my (@bad_styles) = $style_section =~ m/

    \.(\w+)\s*\{display:\s*none\}
  /isxg;

  my $bad_styles = join("|", @bad_styles);

  $html =~ s{<div .+? </div>}{}isxg;
  $html =~ s{<span style="display:none">.+?</span>}{}g;
  $html =~ s{<style>.+?</style>}{};
  $html =~ s{^<span>|</span>$}{}g;
  $html =~ s{<span class="(?:$bad_styles)">.+?</span>}{}g;
  $html =~ s{</?[^>]+>}{}g;

  $ip = $html;

  return $ip;
}
5

BeautifulSoup 这个工具不能分辨网页上可见的文字和其他文字。某些网站在代码上做得很复杂,让抓取网页内容变得更加困难。虽然你可以尝试理解哪些文字是可见的,但这并不简单,因为网页中有很多不相关的元素,这些元素可以通过 styleclass 直接隐藏。有些 IP 部分是在 span 标签里,有些则根本没有标签。

一种解决办法是使用 Selenium,这个工具可以只抓取可见的文字。例如,下面的代码可以打印出特定表格中的所有 IP

from selenium.webdriver.firefox import webdriver

browser = webdriver.WebDriver()
browser.get('https://www.hidemyass.com/proxy-list')

rows = browser.find_elements_by_xpath('//table[@id="listtable"]//tr')
for row in rows[1:]:
    cells = row.find_elements_by_tag_name('td')
    print cells[1].text

browser.close()

另外,你可以参考:

希望这些信息对你有帮助。

撰写回答