Day16 - 完成爬虫功能

在完成基础的表单画面後,接着需要将之前完成的爬虫功能整合至网站。

考量功能的独立性、扩充性和使用便利性,这次预计将爬虫功能打包成一个套件,今天的实作内容则为套件开发。

架构

  1. bookcrawler.py:提供使用者建立爬虫物件。

  2. plugin:放置plugin的资料夹。

    • wwwjjwxc_bookcrawler.py:实作www.jjwxc.net的方法。

https://ithelp.ithome.com.tw/upload/images/20210928/20141886mrYWZsGD6d.png

bookcrawler.py

宣告BookCrawler类别,作为使用者可以建立的物件。

  • init(self, url): 建立物件时需由使用者输入URL,物件初始化流程包含:

    1. 属性的初始化

    2. URL大小写转换,确保资料品质

    3. URL解析,取得网域

    4. 根据网域选择合适的plugin

  • getinfo():任务为执行对应plugin中的实际的getinfo(),并将plugin中取得的网站资讯写进主体。

import re
from crawler.plugin.wwwjjwxc_bookcrawler import wwwjjwxc_BookCrawler

class BookCrawler:
  def __init__(self, url):
    self.authorname = None
    self.title = None
    self.totalsection = 0
    self.url = url.lower()
    regex = r'(https?:\/\/)([\da-z\.-]+\.[a-z\.]{2,6})([\/\w \.-]*)*\/'
    self.domain = re.search(regex, self.url).group(2)

    # 依网域选择plugin
    ### 暂时先hardcode ###
    if self.domain == 'www.jjwxc.net':
      self.plugin = wwwjjwxc_BookCrawler(self.url)
    else:
      self.plugin = None
    #####################

    # 若找不到插件,设定valid = False,表示此网站不支援
    if self.plugin is None:
      self.valid = False
    else:
      self.valid = True

  def getinfo(self):
    self.plugin.getinfo()
    self.authorname = self.plugin.authorname
    self.title = self.plugin.title
    self.totalsection = self.plugin.totalsection

plugin资料夹

因各网站的HTML格式皆不相同,对应不同网域需要使用不同的plugin实作。

为了方便管理,便将各网站的plugin皆放置於此资料夹。

abstractclass.py

宣告抽象类别,定义plugin类别应有的属性与方法。
未来开发的每支plugin程序都应继承此抽象类别,由此来控管plugin属性和方法的一致性。

class AbstractBookCrawler:
  def __init__(self, url):
    self.authorname = None
    self.title = None
    self.url = url
    self.totalsection = 0

  def getinfo():
    pass

wwwjjwxc_bookcrawler.py

此程序实作了www.jjwxc.net的方法。

  • init(self, url):主要继承母类别的初始化。为了处理HTML乱码问题,另外定义了encoding属性使用。

  • getinfo():爬虫程序的本体。

import requests
import re
from bs4 import BeautifulSoup
from crawler.plugin.abstractclass import AbstractBookCrawler

class wwwjjwxc_BookCrawler(AbstractBookCrawler):
  def __init__(self, url):
    super().__init__(url)
    self.encoding = 'gb18030'

  def getinfo(self):
    page = requests.get(self.url)
    page.encoding = self.encoding

    soup = BeautifulSoup(page.content, 'html.parser')
    title_tag = soup.find("span",itemprop="articleSection")
    author_tag = soup.find("span", itemprop="author")
    totalsection_tag = soup.find_all("tr", itemprop=["chapter","chapter newestChapter"])

    self.title = re.compile(r'>(.*)<').search(str(title_tag)).group(1)
    self.authorname = re.compile(r'>(.*)<').search(str(author_tag)).group(1)
    self.totalsection = totalsection_tag.__len__()

<<:  [Day 13]每天前进一点应该也是进步吧?(後端篇)

>>:  Day 28 - Android Studio使用GitHub连接

【在 iOS 开发路上的大小事-Day16】透过 Firebase 来管理使用者 (Sign in with E-mail 篇) Part2

昨天我们已经将注册帐号、帐号登入实作完成了,今天我们要来把剩下的帐号登出以及密码重设功能来实作完成 ...

{DAY 18} Pandas 学习笔记part.4

前言 今天要接续DataFrame的介绍 这篇文章会分成两个部分: 资料的删除 资料的新增 会利用k...

Day 14【连动 MetaMask - Front-End Request and Fetch】Modern problems require modern solutions

【前言】 嗨嗨感谢大家愿意看到这里,接下来要说的是前端的呼叫以及资料传递。今天的内容大部份都参考来...

​ 疫情下的BCP对策

企业或机构日常管理铁三角 1. 合理化:做该做的事、花该花的钱 (1). 省小钱花大钱,乱省一通得不...

[Day4] Vite 出小蜜蜂~ Input Control 操作系统!

Day4 接下来卡比要是着操作 LaserCannon,让他可以左右移动。 Input 在上个章节,...