首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用BeautifulSoup抓取月食/日食数据

利用BeautifulSoup抓取月食/日食数据
EN

Code Review用户
提问于 2018-05-27 00:31:48
回答 2查看 207关注 0票数 7

我创建了一个脚本来抓取网站并收集eclipse数据(日期、类型和位置):

代码语言:javascript
复制
class Eclipse():

    def __init__(self, eclipse_date, eclipse_type, eclipse_location):
        self._eclipse_date = eclipse_date
        self._eclipse_type = eclipse_type
        self._eclipse_location = eclipse_location

    @property
    def get_eclipse_date(self):
        return self._eclipse_date

    @property
    def get_eclipse_type(self):
        return self._eclipse_type

    @property
    def get_eclipse_location(self):
        return self._eclipse_location

    def __str__(self):
        return "Date: {0} Type {1} Location: {2}" .format(self._eclipse_date,self._eclipse_type,self._eclipse_location)

主类

代码语言:javascript
复制
import requests
from bs4 import BeautifulSoup
from Eclipse import Eclipse
from collections import namedtuple


def generate_eclipse_data(eclipse_info):

    eclipse_list = []

    for info in eclipse_info:
       eclipse_date_and_type = info.find('a').text
       retrieved_date_and_type = generate_date_and_type(eclipse_date_and_type)
       eclipse_location = info.find('p').text
       retrieved_location_data = generate_location(eclipse_location)
       eclipse_data = Eclipse(retrieved_date_and_type.date,retrieved_date_and_type.type,retrieved_location_data.location)
       eclipse_list.append(eclipse_data)
    return eclipse_list

def generate_location(info_to_clean):
   clean_location = namedtuple("Clean_Location",["location"])
   cleanup_location = info_to_clean.split(" New Features")[0]
   location_data = clean_location(cleanup_location)
   return location_data


def generate_date_and_type(info_to_split):
   date_and_type = namedtuple("Date_Type", ["date", "type"])
   eclipse_split_data = info_to_split.split("—")
   eclipse_date = eclipse_split_data[0]
   eclipse_type = eclipse_split_data[1].strip()
   eclipse_data = date_and_type(eclipse_date,eclipse_type)
   return eclipse_data

def write_data_to_file(filename, data):
    with open(filename, 'w') as eclipse_writer:
        for info in data:
            eclipse_writer.write(str(info))
            eclipse_writer.write("\n")


def main():

    eclipse_time_date = requests.get("https://www.timeanddate.com/eclipse/")
    soup = BeautifulSoup(eclipse_time_date.text, 'html.parser')
    eclipse_info = soup.find_all("div", class_= "six columns art__eclipse-txt")
    eclipse_filename = 'eclipse.txt'

    if (len(eclipse_info) > 0):
        eclipse_data =  generate_eclipse_data(eclipse_info)
        write_data_to_file(eclipse_filename, eclipse_data)
    else:
        print("No data available")

if __name__ == "__main__":
    main()

输出

代码语言:javascript
复制
Date: July 13, 2018 
Type: Partial Solar Eclipse
Location: South in Australia, Pacific, Indian Ocean

Date: July 27, 2018 
Type: Total Lunar Eclipse
Location: Much of Europe, Much of Asia, Australia, Africa, South in North America, South America, Pacific, Atlantic, Indian Ocean, Antarctica

问题:

  1. 在命名变量和函数时,我尽量做到描述性强。够清楚了吗?
  2. 我可以进一步改进脚本吗?
EN

回答 2

Code Review用户

回答已采纳

发布于 2018-05-27 05:53:39

关于Eclipse类:

  1. 在名称中使用"eclipse“是多余的。不过,请注意,datetype都不是好名字,因为它们通常都有不同的含义。一个常见的模式(但也不令人满意)是在名称之后添加下划线,如在type_中使用特殊的单词作为变量或参数名。
  2. 在Java等语言中,我可能会将属性设置为私有属性,但正如您可能已经注意到的那样,在Python中这样做更像是一种可维护性的权衡。避免使用@property方法,并将属性命名为与构造函数参数相同的属性,这大大简化了代码。
  3. 这个类只是一个容器,没有逻辑,只有一点字符串格式。可以提出这样的论点:如果将代码替换为dict,那么代码会更简单一些。
  4. 您实际上没有使用任何get_eclipse_方法。

关于主要档案:

  1. 许多名称,如eclipse_infoinfo_to_cleandata都很模糊,并且没有封装它们包含的内容。在某些情况下,您会发现这是因为它们是两个更清晰定义的事物之间的任意中间步骤,在这种情况下,它们的处理可能通过不同的拆分而得到改进,或者它们确实可以在上下文中被更清楚地命名。例如,作为eclipse_data传递给write_data_to_filedata实际上是字符串列表,或者更准确地说是Eclipses的列表,而不是任意的二进制blob。
  2. generate_date_and_type中,您可以将几行合并成一个: eclipse_date,eclipse_type =info_to_split.strip().split(“-”)
  3. 与其将结果写入文件,不如简单地考虑对其进行print处理。这使得您的工具更容易(更快)使用其他shell工具进行交互,使用重定向将结果直接写入文件仍然很简单。

常规:

  1. 这段代码可以从类型暗示中受益。这也会经常强调应该更改的名称。
  2. 如果我正在处理这个问题,我可能会使用IDE将整个程序压缩成一个函数,并查看是否有明显的类或方法显示自己。当构建一个更大的系统时,分裂和抽象有很大的价值,但是现在您已经有了一个工作程序,看起来可以将整个系统压缩成大约20条可理解的行。
票数 2
EN

Code Review用户

发布于 2018-05-27 09:53:03

首先,Eclipse类的getter是完全多余的。直接使用值。您还可以使用AttrDict作为基类或名称元组来实现相同的行为。其思想是:没有非平凡行为的类可以使用标准数据类(取决于您的更大项目的标准化程度,尽管-一致性可能很重要)。

也许,像generate_date_and_type这样的辅助函数可以在字典上操作(除非它们也在模块之外使用):这个名称太麻烦了。

这里有很多infolistdata的单词。试着给出更好的名字,而不是那些垃圾词:一切都是信息或数据。表义可以用复数名词来表达。而且,generate似乎不合适:它不是生成的。也许,parse是一个更好的词。干净的代码书有一章关于良好的命名。

我使用了正则表达式而不是这个:

代码语言:javascript
复制
   eclipse_split_data = info_to_split.split("—")
   eclipse_date = eclipse_split_data[0]
   eclipse_type = eclipse_split_data[1].strip()

至于把几句话合二为一:我不同意第一个答案。它们自己行上的值有助于调试,也有助于代码的可读性。

注意:在处理非ASCII编码时最好使用Unicode,我指的是"—"。当然,脚本在开始时也应该使用编码指令来标记:# -*- coding: utf-8 -*-

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/195245

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档