命名元组转换为数据框

6
我正在从YouTube频道和视频中检索元数据。
一切都很顺利,但目前我正在努力将所有信息放入所需的数据框中。以下是我使用的代码,来自此Github https://gist.github.com/andkamau/0d4e312c97f41a975440a05fd76b1d29
import urllib.request
import json
from bs4 import BeautifulSoup
from collections import namedtuple
import pafy
from pandas import *
import pandas as pd

df = pd.DataFrame() 
Video = namedtuple("Video", "video_id title duration views thumbnail Description")

def parse_video_div(div):
    video_id = div.get("data-context-item-id", "")
    title = div.find("a", "yt-uix-tile-link").text
    duration = div.find("span", "video-time").contents[0].text
    views = str(div.find("ul", "yt-lockup-meta-info").contents[0].text.rstrip(" views").replace(",", ""))
    img = div.find("img")
    videoDescription = pafy.new("https://www.youtube.com/watch?v="+video_id)
    thumbnail = "http:" + img.get("src", "") if img else ""
    Description = videoDescription.description
    l = Video(video_id, title, duration, views, thumbnail, Description)
     
     # storing in the dataframe
     
    df = pd.DataFrame(list(Video(video_id, title, duration, views, thumbnail, Description)))
    return Video(video_id, title, duration, views, thumbnail, Description)

def parse_videos_page(page):
    video_divs = page.find_all("div", "yt-lockup-video")
    return [parse_video_div(div) for div in video_divs]

def find_load_more_url(page):
    for button in page.find_all("button"):
        url = button.get("data-uix-load-more-href")
        if url:
            return "http://www.youtube.com" + url

def download_page(url):
    print("Downloading {0}".format(url))
    return urllib.request.urlopen(url).read()

def get_videos(username):
    page_url = "http://www.youtube.com/channel/{0}/videos".format(username)
    page = BeautifulSoup(download_page(page_url))
    videos = parse_videos_page(page)
    page_url = find_load_more_url(page)
    while page_url:
        json_data = json.loads(str(download_page(page_url).decode("utf-8")))
        page = BeautifulSoup(json_data.get("content_html", ""))
        videos.extend(parse_videos_page(page))
        page_url = find_load_more_url(BeautifulSoup(json_data.get("load_more_widget_html", "")))
    return videos

if __name__ == "__main__":
    videos = get_videos("UC-M9eLhclbe16sDaxLzc0ng")
    for video in videos:
        print(video)
    print("{0} videos".format(len(videos)))

函数parse_video_div(div)包含所有信息和我的dataframe。但不幸的是,dataframe没有返回任何内容。也许我需要以某种方式循环使用namedtuple

有什么线索可以帮助我实现dataframe看到我的数据吗?


你在 parse_video_div 函数中没有返回你的数据框。所以你将视频转换为变量 df 中的数据框,然后却没有对它进行任何操作。 - grofte
1个回答

16
< p > pd.DataFramenamedtuple 配合使用时效果完美,实际上可以构建列。

示例数据:


示例数据:

In [21]: Video = namedtuple("Video", "video_id title duration views thumbnail De
    ...: scription")
In [22]: In [20]: pd.DataFrame(data=[Video(1, 'Vid Title', 5, 10, 'Thumb',' Des'
    ...: )])
Out[22]: 
   video_id      title  duration  views thumbnail Description
0         1  Vid Title         5     10     Thumb         Des

由于您的函数实际上未返回df并且在代码中没有其他地方使用它,您如何确定它为空?

更新

您只需要编辑parse_video_div的返回值以返回一个pd.DataFrame,并在get_videos函数中将列表连接成一个单独的pd.DataFrame

以下是所做的编辑内容。

def parse_video_div(div):


    #####
    return pd.DataFrame(data=[Video(video_id, title, duration, views, thumbnail, Description)])
    # shorter version
    # return pd.DataFrame(data=[l])

def get_videos(username):
    ####
    videos_df = pd.concat(videos, ignore_index=True)
    return videos_df # return the DataFrame

你需要在最后加上一个连接函数。在 parse_page_div 中,你可以返回任何 pd.DataFrame 输入,让它是 dictpd.Seriesnamedtuple,甚至是一个列表。在这个例子中,我选择了一个 pd.DataFrame 来简化操作,但是从性能方面来看,它可能会增加一些毫秒的处理时间。


我正在努力将所有数据放入函数parse_video_div中的一个dataframe并返回它,以便稍后可以将dataframe用于进一步的数据分析。@iDrwish - Jazz
@Jazz,请检查更新后的答案,我相信它解决了你的问题。 - iDrwish
1
抱歉回复晚了,因为我正在运行您建议的更改。它神奇地生效了!非常感谢您! :) 我将其标记为已纠正答案 :) - Jazz
1
谢谢你的回答!我一直都是显式地使用 pd.DataFrame.from_records(records, columns=Record._fields),但现在我知道我可以更简洁地写。有点惊讶文档没有明确指出这个选项,所以可能会向 pandas 提交一个 PR,以便更清楚地包含它。 - Energya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接