【问题标题】:Slicing function on <for> loop<for> 循环上的切片功能
【发布时间】:2019-12-21 20:22:57
【问题描述】:

我是一名初学者,在带有 Visual Code Studio 的 Windows 10 上使用 python 3.7.1。

作为练习,我尝试从网页中抓取一些由表格组织的数据。

现在,我只想提取一些信息,这些信息嵌套在 &lt;td valign="top" style="width:25%;"&gt;Parte edibile, %&lt;/td&gt;&lt;td align="left" valign="top" style="font-weight:bold;"&gt;75&lt;/td&gt; 值。作为这里的分隔符,我有&lt;td&gt; ... &lt;/td&gt;

我确实尝试了很多方法来只获取每行的第一和第二,因为第三对我来说并不有趣,这只是浪费我不需要的内存。

为此,我使用了一个“for”循环,但正如我通过 BeautifulSoup 电子表格所理解的那样,当它需要一个循环时,每一行的所有嵌套参数都合并为一个,因此如果我想要切片 [0: 1] = >> 第一个和第二个“字符串”参数&lt;td&gt; &lt;/td&gt;,是不可能的。

这是简单的循环'for':

for alim in soup.find_all('td')[0:1]: return alim.text

我说的对吗?任何人都可以向我提出一些更聪明的解决方案来解决我的问题?

提前感谢您的任何建议。 最大

【问题讨论】:

  • 数据是什么形式的,字符串?
  • 如果您想要第一个第二个项目,请改用soup.find_all('td')[0:2]
  • @Artog,是的,它是一个字符串。
  • @Anwarvic,我一直在使用您的建议,但它不适用于我的文本。这就是我一直在这里发帖的原因,这对我来说也很奇怪。无论如何感谢您的帮助!

标签: python html web-scraping beautifulsoup slice


【解决方案1】:

如果我理解正确,您有超过 3 列的表格,并且您只对前两列感兴趣。

要从前两列中提取数据,您有多种可能性。一种是使用 CSS 选择器:

data = '''
    <table>
    <tr>
        <td valign="top" style="width:25%;">I. Parte edibile, %</td>
        <td align="left" valign="top" style="font-weight:bold;">I. 75</td>
        <td>This doesn't interest me</td>
    </tr>
    <tr>
        <td valign="top" style="width:25%;">II. Parte edibile, %</td>
        <td align="left" valign="top" style="font-weight:bold;">II. 75</td>
        <td>II. This doesn't interest me</td>
    </tr>
    <tr>
        <td valign="top" style="width:25%;">III. Parte edibile, %</td>
        <td align="left" valign="top" style="font-weight:bold;">III. 75</td>
        <td>III. This doesn't interest me</td>
    </tr>
    </table>'''

from bs4 import BeautifulSoup

soup = BeautifulSoup(data, 'html.parser')

for col1, col2 in zip(soup.select('td:nth-of-type(1)'), soup.select('td:nth-of-type(2)')):
    print('{: <25} {}'.format(col1.text, col2.text))

打印:

I. Parte edibile, %       I. 75
II. Parte edibile, %      II. 75
III. Parte edibile, %     III. 75

或者你可以使用列表切片:

rows = []
for tr in soup.select('tr'):
    rows.append([td.text for td in tr.select('td')[0:2]])

for row in rows:
    print('{: <25} {}'.format(*row))

编辑:要解析页面http://www.bda-ieo.it/test/ComponentiAlimento.aspx?Lan=Ita&amp;foodid=1300_2,您可以使用以下代码:

from bs4 import BeautifulSoup
import requests

url = 'http://www.bda-ieo.it/test/ComponentiAlimento.aspx?Lan=Ita&foodid=1300_2'

soup = BeautifulSoup(requests.get(url).text, 'html.parser')

for col1, col2 in zip(soup.select('#tblComponenti > tr.testonormale > td:nth-of-type(1)'), soup.select('#tblComponenti > tr.testonormale > td:nth-of-type(2)')):
    print('{: <70} {}'.format(col1.text, col2.text))

打印:

Parte edibile, %                                                       75
Energia, ricalcolata, kJ                                               406
Energia, Ric con fibra, kJ                                             406
Energia, ricalcolata, kcal                                             96
Energia, Ric con fibra, kcal                                           96
Proteine totali, g                                                     16,8
   Proteine animali, g                                                 16,8
   Proteine vegetali, g                                                0,0
Lipidi totali, g                                                       2,6
   Lipidi animali, g                                                   2,6
   Lipidi vegetali, g                                                  0,0
Colesterolo, mg                                                        61
Carboidrati disponibili (MSE), g                                       1,5
   Amido (MSE), g                                                      0,0
   Carboidrati solubili (MSE), g                                       1,5
Fibra alimentare totale, g                                             0,0
Alcol, g                                                               0,0
Acqua, g                                                               76,5
Ferro, mg                                                              2,8
Calcio, mg                                                             148
Sodio, mg                                                              104
Potassio, mg                                                           278
Fosforo, mg                                                            196
Zinco, mg                                                              4,20
Magnesio, mg                                                           22
Rame, mg                                                               1,00
Selenio, µg                                                            37,0
Cloro, mg                                                              130
Iodio, µg                                                              29
Manganese, mg                                                          0,07
Zolfo, mg                                                              150
Vitamina B1, Tiamina, mg                                               0,06
Vitamina B2, Riboflavina, mg                                           0,26
Vitamina C, mg                                                         0
Niacina, mg                                                            14,00
Vitamina B6, mg                                                        0,14
Folati totali, µg                                                      9
Acido pantotenico, mg                                                  0,65
Biotina, µg                                                            6,0
Vitamina B12, µg                                                       0,6
Retinolo equivalente                                                   32
   Retinolo eq. (RE), µg                                               32
   Retinolo, µg                                                        tr
   ß-carotene eq., µg                                                  0,29
Vitamina E (ATE), mg                                                   11,00
Vitamina D, µg                                                         1,30
Acidi grassi saturi totali, g                                          0,00
Somma degli acidi butirrico, caproico, caprilico e caprico, g          0,00
Acido laurico, g                                                       0,14
Acido miristico, g                                                     1,01
Acido palmitico, g                                                     0,13
Acido stearico, g                                                      tr
Acido arachidico, g                                                    0,00
Acido beenico, g                                                       0,40
Acidi grassi monoinsaturi totali, g                                    0,00
Acido miristoleico, g                                                  0,10
Acido palmitoleico, g                                                  0,17
Acido oleico, g                                                        0,01
Acidi eicosenoico, g                                                   0,01
Acido erucico, g                                                       0,85
Acidi grassi polinsaturi totali, g                                     0,01
Acido linoleico, g                                                     0,01
Acido linolenico, g                                                    tr
Acido arachidonico, g                                                  0,27
Acido eicosapentaenoico (EPA), g                                       0,52
Acido decosaesaenoico (DHA), g                                         0,04
Altri acidi grassi polinsaturi, g                                      175
Triptofano, mg                                                         726
Treonina, mg                                                           823
Isoleucina, mg                                                         1330
Leucina, mg                                                            1379
Lisina, mg                                                             349
Metionina, mg                                                          183
Cistina, mg                                                            595
Fenilalanina, mg                                                       425
Tirosina, mg                                                           759
Valina, mg                                                             758
Arginina, mg                                                           675
Istidina, mg                                                           919
Alanina, mg                                                            1764
Acido aspartico, mg                                                    2261
Acido glutammico, mg                                                   722
Glicina, mg                                                            460
Prolina, mg                                                            650
Serina, mg                                                             1,5
Glucosio, g                                                            0,0
Fruttosio, g                                                           0,0
Galattosio, g                                                          0,0
Saccarosio (MSE), g                                                    0,0
Maltosio (MSE), g                                                      0,0

【讨论】:

  • 非常感谢安德烈!我感谢您的帮助。您能否指出我应该在哪里深入学习您的解决方案?是在 BeautifulSoup 文档中还是在 Python 指南中?
  • @Massimo 我将从 BeautifulSoup 的文档 crummy.com/software/BeautifulSoup/bs4/doc 开始学习 CSS 选择器 w3schools.com/cssref/css_selectors.asp 也很有用 - 您不仅可以在 BeautifulSoup 中使用它们,还可以在 Javascript 等中使用它们。
  • @Massimo 是的,您可以创建一个返回列表的函数,而不是打印。这取决于您的用例。
  • 伟大而有用的建议 Andrej,非常感谢。我将深入了解它。祝你 8 月 15 日愉快:)
  • @Massimo 我编辑了我的答案。有很多嵌套的&lt;table&gt;,所以我稍微改变了一个CSS选择器
【解决方案2】:

如果返回类型是一个列表,你应该使用[0:2],因为最终的数字是不包含在内的(但是返回会跳出循环)所以需要稍微改变一下:

result = []
for alim in soup.find_all('td')[0:2]:
     result.append(alim.text)
return result

【讨论】:

  • 感谢 Joshua,我也一直在尝试您的解决方案,它看起来真的很像 Python zen 方式。但这对我不起作用,我仍然不知道我不明白什么。您的解决方案打印出文本,但仍然包含我不想要的文本,而且它没有按行顺序排序。我在文本中看到它出现在每个新文本行中的“\n”,但不在新行中。我希望我解释得足够清楚。知道我的代码有什么问题吗?
【解决方案3】:

有几种方法可以取前两个元素:

1) 使用带有 getattr 的 map 函数,我喜欢这种方式,因为您只迭代前 2 个元素

from bs4 import BeautifulSoup

soup = BeautifulSoup(your_html, 'lxml') 
r = soup.find_all('td')
gen_my_soup_text = map(lambda x: getattr(x, 'text'), r)

first_string = next(gen_my_soup_text)
second_string = next(gen_my_soup_text)

print(first_string)
print(second_string)

# output: 
# Parte edibile, %
# 75

2) 使用切片和映射

list(map(lambda x: getattr(x, 'text'), r))[:2]

3) 使用列表理解和切片

[e.text for e in r][:2]

要抓取您的网页,您可以尝试:

from bs4 import BeautifulSoup
import requests


req = requests.get('http://www.bda-ieo.it/test/Alphabetical.aspx?Lan=Ita')
soup =  BeautifulSoup(req.text, "lxml")

# result is the container of the tags of interest.
rows = soup.find_all("tr", attrs = {'class':'testonormale'})
first_second = [[e.text for e in row.find_all('td')][:2] for row in rows]

# output: 
#[['1300', 'ACCIUGHE o ALICI '],
# ['1502', 'ACCIUGHE o ALICI SOTTO SALE'],
# ['1501', "ACCIUGHE o ALICI SOTT'OLIO"],
# ['100205', 'ACETO'],
....
# ['602004', 'ASTICE '],
# ['600009', 'AVENA '],
# ['999692', 'AVOCADO ']]

【讨论】:

  • 谢谢 rusu_ro1。我假设您的第三个解决方案是唯一一个带有“for”循环的解决方案,如果我理解正确的话,但我不明白它是如何工作的。我将循环嵌套到函数“def”中。我做错了什么?
  • 我也尝试过您的第二个建议,但同样,我得到了错误的输出。输出没有切掉第三个 ....,似乎它都粘在一行中,包括所有 ..,实际上如果我使用它不会改变任何东西切片 [0:2] 或 [0:4 或 5 ..] 输出是相同的 :( 知道我的代码有什么问题吗?
  • 请给我网页好吗
  • 谢谢 rusu,感谢您的帮助,尽管 Andrej 的反馈更符合我的目标。
猜你喜欢
  • 2021-03-28
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-01
  • 2021-06-16
  • 2012-08-18
  • 2020-10-05
相关资源
最近更新 更多