后端 【Day 15】数据持久化

xerfect · August 12, 2021 · 1 hits

今天来试着把我们从列表页开始,一路抓到的文章内容和信息都存到数据库中!

突然想到还没整理过完整流程的原代码,先来整理一下呗~

import requests
from bs4 import BeautifulSoup
from datetime import datetime
import re

def crawl_list():
    """爬取文章列表页
    """
    # 抓取 1~10 页
    for page in range(1, 11):
        html_doc = requests.get(f'https://ithelp.ithome.com.tw/articles?tab=tech&page={page}').text
        soup = BeautifulSoup(html_doc, 'lxml')

        # 先找到文章区块
        article_tags = soup.find_all('div', class_='qa-list')

        # 没有文章
        if len(article_tags) == 0:
            # 跳出换页循环或离开程序
            print('没有文章了!')
            break

        for article_tag in article_tags:
            # 再由每个区块去找文章链接
            title_tag = article_tag.find('a', class_='qa-list__title-link')
            article_url = title_tag['href']

            crawl_content(article_url)

def crawl_content(url):
    """爬取文章内容

    :param url: 文章链接
    """
    html_doc = requests.get(url).text
    soup = BeautifulSoup(html_doc, 'lxml')

    leftside = soup.find('div', class_='leftside')
    original_post = leftside.find('div', class_='qa-panel')

    article_header = original_post.find('div', class_='qa-header')
    article_info = article_header.find('div', class_='ir-article-info__content')

    # 标题
    title = article_header.find('h2', class_='qa-header__title').get_text(strip=True)

    # 作者
    author = article_info.find('a', class_='ir-article-info__name').get_text(strip=True)

    # 发文时间
    published_time_str = article_info.find('a', class_='ir-article-info__time').get_text(strip=True)
    published_time = datetime.strptime(published_time_str, '%Y-%m-%d %H:%M:%S')

    # 文章标签
    tag_group = article_header.find('div', class_='qa-header__tagGroup')
    tags_element = tag_group.find_all('a', class_='tag')
    tags = [tag_element.get_text(strip=True) for tag_element in tags_element]

    # 内文
    content = original_post.find('div', class_='markdown__style').get_text(strip=True)

    # 浏览数
    view_count_str = article_info.find('div', class_='ir-article-info__view').get_text(strip=True)
    view_count = int(re.search('(\\d+).*', view_count_str).group(1))

    article = {
        'url': url,
        'title': title,
        'author': author,
        'publish_time': published_time,
        'tags': tags,
        'content': content,
        'view_count': view_count
    }
    print(article)

if __name__ == '__main__':
    crawl_list()

把上面这段代码存成 ithome_crawler.py 文件后,进入虚拟环境运行。

因为代码越来越长,决定之后都存成 .py 文件后再运行了

https://d1dwq032kyr03c.cloudfront.net/upload/images/20190930/20107875kbpTrzF4xr.png

crawl_content(url) 方法的最后,直接把每篇文章都 print 出来,如果要把数据存进数据库,就从这边开始做修改吧!

创建添加方法

因为目的地数据库可能会有不同环境,例如从 PostgreSQL 变成 MySQL,或者变成后面几天会提到的 MongoDB,所以这边可以把与数据库有关的逻辑独立成一个方法,跟原本爬取的逻辑分开来,未来比较好维护。

import psycopg2

host = 'localhost'
user = 'postgres'
dbname = 'ithome2019'
password = '<server_admin_password>'
conn_string = f'host={host} user={user} dbname={dbname} password={password}'
conn = psycopg2.connect(conn_string)
print('数据库连接成功!')

cursor = conn.cursor()

def crawl_content(url):
    """爬取文章内容

    :param url: 文章链接
    """
    # ...略

    insert_db(article)

def insert_db(article):
    """把文章插入到数据库中

    :param article: 文章数据
    """
    cursor.execute('''
    INSERT INTO public.ithome_article(title, url, author, publish_time, tags, content)
    VALUES (%(title)s,%(url)s,%(author)s,%(publish_time)s,%(tags)s,%(content)s);
    ''',
    article)

    print(f'[{article["title"]}] 添加成功!')

    conn.commit()

cursor.close()
conn.close()

https://d1dwq032kyr03c.cloudfront.net/upload/images/20190930/20107875ME5lf3XEwt.png

增加字段

突然发现少开一个浏览数的字段,赶快补上去吧!

在要加字段的数据表上按「右键 > Create > Column」,填入对应的信息后按「Save」。

https://d1dwq032kyr03c.cloudfront.net/upload/images/20190930/20107875qVosbGhXSK.png

https://d1dwq032kyr03c.cloudfront.net/upload/images/20190930/20107875KEqbzhPMbd.png

https://d1dwq032kyr03c.cloudfront.net/upload/images/20190930/201078758eBVpcBNkK.png

修改原本的 insert 语法后再运行,就可以看到刚刚抓下来的这些数据啰!

def insert_db(article):
    """把文章插入到数据库中

    :param article: 文章数据
    """
    cursor.execute('''
    INSERT INTO public.ithome_article(title, url, author, publish_time, tags, content, view_count)
    VALUES (%(title)s,%(url)s,%(author)s,%(publish_time)s,%(tags)s,%(content)s,%(view_count)s);
    ''',
    article)

    print(f'[{article["title"]}] 添加成功!')

    conn.commit()

https://d1dwq032kyr03c.cloudfront.net/upload/images/20190930/20107875Ueo8qZVJVA.png


今天的完整代码有放在 gist 上了,有兴趣的读者可以上去看看。

明天会接着把回文的数据也存到数据库中~


No Reply at the moment.
You need to Sign in before reply, if you don't have an account, please Sign up first.