python-3.x 在使用Beautiful Soup进行刮取时,如何正确存储 Dataframe 所属行/单元格中的值?

dxpyg8gm  于 2022-12-05  发布在  Python
关注(0)|答案(1)|浏览(110)

所以,我试着从日记里搜集数据。
虽然我可以成功地抓取论文的标题、关键词等,并在收集作者姓名时将它们正确地保存在 Dataframe 中,但在第一篇论文之后,每一篇论文提到的作者都存储在一个新行中
很明显,这会使存储的数据变得无用和不相关,因此,我得到的不是相同的行数,而是一个无用的 Dataframe 。
据我所知,出现此问题的原因是程序不“知道”将与每篇论文相关的所有数据存储在单独的行中。此外,有些论文只有一个作者,而其他论文有3-4个作者。例如,作者需要以“NameSurname,NameSurname,NameSurname...”格式存储在包含每篇研究论文信息的单独行中:作者、所属机构等
但是,当涉及到指定我打算抓取的类时,我不确定如何正确地设置Python(BS 4)代码。
下面是简单scraper的相关代码片段:

title = []
authors = []
afiliations = []

for i in urls: 
    page = requests.get(link)
    content = page.text
    soup = BeautifulSoup(content, "html.parser")
    for t in soup.select(".obj_article_details .page_title"):
        title.append(t.get_text(strip=True))
    for au in soup.select(".obj_article_details .authors .name"):
        authors.append(au.get_text(strip=True))
    for af in soup.select(".obj_article_details .item.authors .affiliation"):
        affiliations.append(af.get_text(strip=True))
    time.sleep(3)

另外,这里有一个我打算刮去的截面结构。

...
<article class="obj_article_details">   
 <h1 class="page_title">
   Lorem ipsum dolor sit amet
 </h1>
  <div class="row">
   <div class="main_entry">
<section class="item authors">
  <ul class="authors">
    <li>
      <span class="name">Brandon Scott </span>
      <span class="affiliation"> Villanova University, Pennsylvania </span>
    </li>
    <li>
      <span class="name">Alvaro Cote </span>
      <span class="affiliation">Carleton College, Minnesota</span>
    </li>
  </ul>
</section>

...

我现在得到的是:

|Authors       |  Affiliation                       | 
    +--------------+------------------------------------+
    |Brandon Scott | Villanova University, Pennsylvania |
    +--------------+------------------------------------+
    |Alvaro Cote   | Carleton College, Minnesota        |
    +--------------+------------------------------------+
    |...           | ...                                |

我想要的:

|Authors                     |  Affiliation         | 
    +--------------+------------------------------------+
    |Brandon Scott, Alvaro Cote | Villanova University..|
    +--------------+------------------------------------+
    |...           |...                                 |
    +--------------+------------------------------------+
    |...           |...                                 |
enxuqcxy

enxuqcxy1#

对于此类情况,应使用嵌套循环-容器ResultSet的外部循环(此处为soup.select('article.obj_article_details')),和内部循环来获取所需的详细信息- title/author/affiliation/etc。此外,最好为每个容器构建一个详细信息字典,并将其添加到字典列表中,而不是尝试将单独的列表绑定在一起(您已经遇到了该方法所导致的一些问题)。
由于您对每个细节都执行相同的操作(select后跟get_text),因此将这些操作移到如下函数中会更方便

def getText_bySelector(tagSoup, selector, sep=None):
    selTags = tagSoup.select(selector) if selector else [tagSoup]
    if type(sep) == str: 
        return sep.join([s.get_text(' ').strip() for s in selTags])
    return selTags[0].get_text(' ').strip() if selTags else None

(This是this function的一个变体,我在大多数bs 4项目中都使用它。)
如果您将字符串(如,/;/etc)作为sep传递,则它将连接所有结果(如果没有结果,则返回空字符串[""]);否则,它将返回第一个结果(如果没有结果,则返回None)。
我喜欢使用这样的函数的另一个原因是它允许我使用list comprehension而不是最里面的for循环。
然后,您只需要定义一个引用字典,其中包含需要传递给getText_bySelector的参数

refDict = {
    'title': ('.page_title', None), 
    'authors': ('.authors .name', ', '),
    'affiliations': ('.item.authors .affiliation', '; ')
}

现在,您可以使用

dictList = []
for i in urls: 
    page = requests.get(link)
    content = page.text
    soup = BeautifulSoup(content, "html.parser")

    dictList += [{
        k: getText_bySelector(a, vsel, vsep) 
        for k, (vsel, vsep) in refDict.items()
    } for a in soup.select('article.obj_article_details')]

dictList中的项目将如下所示

{
  'title': 'Lorem ipsum dolor sit amet',
  'authors': 'Brandon Scott, Alvaro Cote',
  'affiliations': 'Villanova University, Pennsylvania; Carleton College, Minnesota' 
}

您可以轻松地使用panda将dictList视为表x1c 0d1x

相关问题