【问题标题】:Create a csv thanks to web scraping multiple page with python or pyspark通过使用 python 或 pyspark 抓取多个页面来创建 csv
【发布时间】:2018-02-28 08:53:46
【问题描述】:

我第一次尝试网页抓取一个网站,我想从一个日本动画网站的网页抓取中创建一个 csv 文件,其中包含标题、性别、工作室和动画持续时间。

我只设法用该代码收集了第一页标题的数据:

import requests
from bs4 import BeautifulSoup
res = requests.get("http://www.animeka.com/animes/series/~_1.html")
soup = BeautifulSoup(res.content, "html.parser")
anime_containers = soup.find_all('table', class_ = 'animesindex')
names = []

for container in anime_containers:

    if container.find_all('td', class_ = 'animestxt') is not None:
        name = container.a.text
        names.append(name)
        
import pandas as pd

test_df = pd.DataFrame({'anime': names})
print(test_df)

并得到类似的东西:

anime
0   "Eikou Naki Tensai-tachi" kara no Monogatari
1                                 "Eiyuu" Kaitai
2                              "Parade" de Satie
3                                       ?l DLIVE
4                   'n Gewone blou Maandagoggend
5                                    +Tic Neesan
6                          .hack// Terminal Disc
7                           .hack//G.U. Returner
8                            .hack//G.U. Trilogy

我不知道如何收集性别、工作室和持续时间以及如何在不重复相同代码的情况下抓取所有其他页面

这是页面查看的源代码-source:http://www.animeka.com/animes/series/~_1.html

【问题讨论】:

  • 和?你有什么问题?
  • 我不知道如何收集性别、工作室和持续时间,以及如何在不重复相同代码的情况下抓取所有其他页面,我只从第一页获得数据,有 466 页。

标签: python web-scraping beautifulsoup pyspark


【解决方案1】:

要遍历所有页面,您只需使用 for 循环并更改 url 中的页码,如下所示:

for page_no in range(1, 467):
    url = 'http://www.animeka.com/animes/~_{}.html'.format(page_no)

现在,要获取您想要的信息,您可以使用:

titles, studios, genres, durations = [], [], [], []

for page_no in range(1, 467):
    url = 'http://www.animeka.com/animes/~_{}.html'.format(page_no)
    r = requests.get(url)
    soup = BeautifulSoup(r.text, 'lxml')

    for table in soup.find_all('table', class_='animesindex'):
        td = table.find_all('td', class_='animestxt')
        titles.append(td[1].text.split(':')[1])
        studios.append(td[3].text.split(':')[1])
        genres.append(td[4].text.split(':')[1])
        durations.append(td[6].text.split(':')[1])

headers = ['Title', 'Studio', 'Genres', 'Duration']
df = pd.DataFrame(dict(zip(headers, [titles, studios, genres, durations])))
print(df)

部分输出:

                                            Title                   Duration                                             Genres                                             Studio
0    "Eikou Naki Tensai-tachi" kara no Monogatari    TV-S 25 mins (en cours)                          [SPORT] [TRANCHE DE VIE]                      [NHK ENTERPRISE] [J.C. STAFF] 
1                                  "Eiyuu" Kaitai                      1 OAV                                         [COMéDIE]                                            [ZEXCS] 
2                               "Parade" de Satie             1 FILM 14 mins         [FANTASTIQUE & MYTHE] [COMéDIE] [MUSICAL]                               [YAMAMURA ANIMATION] 
3                                         elDLIVE               Non spécifié         [ACTION] [COMéDIE] [ESPACE & SCI-FICTION]                                 [PIERROT CO.,LTD.] 
4                    'n Gewone blou Maandagoggend              1 FILM 3 mins                                           [DRAME]                                            [AUCUN] 

【讨论】:

  • 有了这个基础,我想获取用户 ID 以及他们对哪个动漫的评分是多少,你有什么想法得到那个,在网站上,评分是在图像中,我不知道如何利用它?
  • 我认为您应该就此提出另一个问题。这超出了这个问题的范围。
【解决方案2】:

这个小程序展示了如何废弃可能不是最佳解决方案的页面,您可以修改它以满足您的需求: (从http://www.animeka.com/animes/series/~_1.htmlhttp://www.animeka.com/animes/series/~_466.html

import requests
from bs4 import BeautifulSoup

animation_list = []
url = "http://www.animeka.com/animes/series/~_1.html"
page_source = requests.get(url).content
soup = BeautifulSoup(page_source, "html5lib")
tag_list = soup.find_all("td", {"class" : "animestxt"})
result_list = []

for tag in tag_list:
    if "TITRE ORIGINAL" in tag.text:
        data_string = tag.text.split("\n")
        tmp_dic = {}
        for index in data_string:
            line = index.strip()
            if len(line) == 0:
                continue
            if not line[0].isalpha():
                continue
            if line not in ["", " ", "  "]:
                tmp_dic[line.split(":")[0]] = line.split(":")[1]
        result_list.append(tmp_dic)

for list_index in result_list:
    if len(list_index) != 6:
        continue
    for item in list_index:
        print("{} : {}".format(item, list_index[item]))
    print("==================")

输出:

TITRE ORIGINAL  :  "Eikou Naki Tensai-tachi" kara no Monogatari
ANNÉE DE PRODUCTION  :  2017
STUDIOS  :  [NHK ENTERPRISE] [J.C. STAFF]
GENRES  :  [SPORT] [TRANCHE DE VIE]
AUTEURS  :  [ITOU TOMOYOSHI] [MORITA SHINGO]
TYPE & DURÉE  :   TV-S 25 mins (en cours)
==================
TITRE ORIGINAL  :  "Eiyuu" Kaitai
ANNÉE DE PRODUCTION  :  2016
STUDIO  :  [ZEXCS]
GENRE  :  [COMéDIE]
AUTEUR  :  [KOYAMA KYOUHEI]
TYPE & DURÉE  :  1 OAV
==================
TITRE ORIGINAL  :  "Parade" de Satie
ANNÉE DE PRODUCTION  :  2016
STUDIO  :  [YAMAMURA ANIMATION]
GENRES  :  [FANTASTIQUE & MYTHE] [COMéDIE] [MUSICAL]
AUTEUR  :  [SATIE ERIK]
TYPE & DURÉE  :  1 FILM 14 mins
==================
TITRE ORIGINAL  :  elDLIVE
ANNÉE DE PRODUCTION  :  2017
STUDIO  :  [PIERROT CO.,LTD.]
GENRES  :  [ACTION] [COMéDIE] [ESPACE & SCI-FICTION]
AUTEUR  :  [AMANO AKIRA]
TYPE & DURÉE  :  Non spécifié
==================
TITRE ORIGINAL  :  'n Gewone blou Maandagoggend
ANNÉE DE PRODUCTION  :  2014
STUDIO  :  [AUCUN]
GENRE  :  [DRAME]
AUTEUR  :  [KAMFER RONELDA]
TYPE & DURÉE  :  1 FILM 3 mins

【讨论】:

  • 我在尝试您的代码时收到“UnicodeEncodeError: 'ascii' codec can't encode character u'\xc9' in position 3: ordinal not in range(128)”。但是,我搜索以获取包含您打印的每个信息的数据框结果,以便将其导出为 csv
  • 嗯,这是一个典型的编码错误,因为文本不包含任何 ASCII 字符。您可以切换到使用 python3.X 或使用 utf-8 或 unicode 编码。可以使用python将程序中的结果直接转换成csv,会有很多解决方案。
【解决方案3】:

图书馆的好选择!我还想推荐使用 urlpath 库来稍微简化请求。

pip install urlpath

试试这个:

from bs4 import BeautifulSoup
from urlpath import URL
import pandas as pd

def scrape_page(url):
    res = url.get()
    soup = BeautifulSoup(res.content, "html.parser")
    anime_containers = soup.find_all('table', {'class':'animesindex'})
    anime_dictionary = {}
    for container in anime_containers:
        anime_name = container.find('td',{'class':'animestitle'}).a.text
        dic = {}
        for td in container.find_all('td', {'class':'animestxt'}):
            attr = [t.strip() for t in td.text.strip().split(':')]
            dic[attr[0]] = ':'.join(attr[1:])
            anime_dictionary[anime_name] = dic
    return anime_dictionary

url = URL('http://www.animeka.com/animes/~_{}.html'.format(1))
anime_dictionary = scrape_page(url)
df = pd.DataFrame(anime_dictionary)
print(df)

此代码适用于单个页面。 scrape_page 函数接受一个 urlpath 对象并使用它来发出请求。我个人喜欢 urlpath 对象,因为它与 pyhton 的 pathlib 对象 urllib 很好地交互,并且内置了请求。从那里,我们将页面解析为 BeautifulSoup 对象。在汤的 find_all 方法中,我传入了一个字典而不是使用关键字参数,因为当将此代码应用于未来项目时,它对于传递多个约束更有用。最终,scrape_page 函数返回一个字典字典,因为它是构造 DataFrame 的一种非常方便的结构,并且直接类似于 DataFrame。

修改该函数的多页使用代码如下:

anime_dictionary = {}
for i in range(466):
    url = URL('http://www.animeka.com/animes/~_{}.html'.format(i+1))
    anime_dictionary.update(scrape_page(url))
df = pd.DataFrame(anime_dictionary)
df.to_csv('file_name.csv')

这点之后的结果将存在于一个相当大的 pandas 数据框中。下面显示了一个结果的条目:

                                       .hack//G.U. Trilogy  \
ANNÉE DE PRODUCTION                                    2008   
ANNÉES DE PRODUCTION                                    NaN   
AUTEUR                                                  NaN   
AUTEURS                [PROJECT .HACK] [SADAMOTO YOSHIYUKI]   
GENRE                                                   NaN   
GENRES                   [ACTION] [AVENTURE] [ANIMATION 3D]   
STUDIO                                                  NaN   
STUDIOS                [CYBERCONNECT2] [BANDAI NAMCO GAMES]   
TITRE ORIGINAL                          .hack//G.U. Trilogy   
TYPE & DURÉE                                 1 FILM 85 mins   
VOLUMES, TYPE & DURÉE                                   NaN 

展望未来,让函数更加动态以能够处理任何带有表格的网页应该不会太难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 2014-12-17
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    相关资源
    最近更新 更多