爬虫案例:股吧

东方财富网股吧爬虫案例

运行环境:

pip install -i https://mirrors.aliyun.com/pypi/simple colorama
pip install -i https://mirrors.aliyun.com/pypi/simple requests
pip install -i https://mirrors.aliyun.com/pypi/simple parsel
pip install -i https://mirrors.aliyun.com/pypi/simple pymysql

MySQL 数据库表结构

create table comment
(
    id          varchar(200) not null primary key,
    read_count  int          null,
    reply       int          null,
    title       varchar(200) null,
    title_url   varchar(200) null,
    author      varchar(200) null,
    author_url  varchar(200) null,
    update_time varchar(200) null
);
create database spiders default character set utf8mb4;

代码分析:

1.构建请求头信息

host:换成你自己的数据地址,一般本地库都是 localhost
user:替换成自己的用户名
database:需要自建一个 spiders 数据库
port:端口号,MySQL 默认 3306
请求头字典里有一个 Cookie 和 Host 在测试的过程中,如果只加一个 User-Agent 返回的结果是 403 状态码,没有特殊反扒,一般情况下补充请求头信息即可。

base_url = 'https://guba.eastmoney.com'
db = pymysql.connect(host='localhost', user='root', password='ambition', database='spiders', port=3306)
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.'
                  '0.0 Safari/537.36',
    'Host': 'guba.eastmoney.com',
    'Cookie': 'Cookie 信息'
}

2.获取内容函数

其中 count 参数是为了分页做准备,在第一页的时候 URL 没有拼接_1 所有做了个判断。

def crawl_content(count=1):
    """
    根据 URL 获取内容
    :param count: 页码
    :return: 获取的 HTML 内容
    """
    url = base_url + '/list,waihui.html'
    if count != 1:
        # count != 1 的时候就是指定页数的评价
        url = base_url + '/list,waihui' + f'_{count}' + '.html'
    try:
        print(Fore.BLACK + '-' * 50, '正在获取:' + url)
        response = requests.get(url, headers=headers)
        # 个人经历的判断
        if response.status_code == http.HTTPStatus.PERMANENT_REDIRECT:  # 请求头信息不全可能会触发 redirect 重定向错误
            print('请检查请求头(headers)信息!!')
            # 最后请求的内容也是空直接结束程序
            sys.exit()
        else:
            if response.text.find('<ul class="tab_content"') > 0:
                return response.text
            else:
                print('-' * 50, '获取的:(' + url + ')内容可能不正确!!')
    except urllib.error.URLError as e:
        print('URLError: ', '\n', url, '\n', e.reason)
        sys.exit()

3.解析内容

css 和 xpath 选择节点根据个人经验来,本人经验不足可能有更简便的写法。

def spider_out_comment(content):
    """
    根据获取的内容解析需要的内容
    :return:
    """
    # with open('1.html', 'r', encoding='utf-8') as file:
    #     content = file.read()
    # 创建 selector 对象读取解析内容
    selector = Selector(text=content)
    list_body = selector.xpath('//li[contains(@class, "defaultlist")]/table[contains(@class, "default_list")]/tbody[c'
                               'ontains(@class, "listbody")]').xpath('.//tr[contains(@class, "listitem")]')
    data = []  # 存储信息
    for item in list_body:
        read_count = item.css('div.read::text').get()  # 阅读量
        reply = item.css('div.reply::text').get()  # 评论数
        title = item.css('div.title > a::text').get()  # 标题
        title_url = item.css('div.title > a').attrib['href']  # 标题对应的链接
        author = item.css('div.author > a::text').get()  # 作者
        author_url = item.css('div.author > a').attrib['href']  # 作者主页
        # 获取更新时间
        update_time = item.xpath('.//div[contains(@class, "update")]/text()').get()
        data.append({
            'id': re.findall('[0-9]+', title_url)[0],
            'read_count': read_count,
            'reply': reply,
            'title': title,
            'title_url': title_url,
            'author': author,
            'author_url': author_url,
            'update_time': update_time
        })
    save_mysql(data)

4.保存解析的内容到数据库

def save_mysql(data):
    """
    保存信息
    :return:
    """
    cursor = db.cursor()
    print(Fore.BLACK + '-' * 50 + '保存获取的信息')
    count = 0
    for i in range(len(data)):
        keys = ', '.join(data[i].keys())  # 使用变量名作为字段名
        values = ', '.join(['%s'] * len(data[i]))
        sql = f'insert into comment ({keys}) values ({values})'
        try:
            cursor.execute(sql, tuple(data[i].values()))
        except pymysql.Error:
            print(Fore.RED, '已经存在了:', data[i]['id'])
            db.rollback()
        else:
            count += 1
            db.commit()
    print(Fore.GREEN + '-' * 50 + '保存成功!共有 ' + str(count) + ' 条')

关注公众号赠送 python 书籍

关注公众号私信001,发送对应书籍。
请添加图片描述

完整代码

注意更换数据库地址,以及 cookie 请求头信息。

import http
import re
import sys
import urllib.error
import requests
import pymysql
from parsel import Selector
from colorama import Fore, init

init()  # 用来调整 print 打印颜色

base_url = 'https://guba.eastmoney.com'
db = pymysql.connect(host='localhost', user='root', password='ambition', database='spiders', port=3306)
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.'
                  '0.0 Safari/537.36',
    'Host': 'guba.eastmoney.com',
    'Cookie': 'HAList=ty-133-USDCNH-%u7F8E%u5143%u79BB%u5CB8%u4EBA%u6C11%u5E01; qgqp_b_id=41cbf4607be7c6b3e4c71fa5bd588'
              '132; websitepoptg_api_time=1710501153250; st_si=57729005964046; st_asi=delete; st_pvi=40258994733769; st'
              '_sp=2024-03-15%2019%3A12%3A33; st_inirUrl=https%3A%2F%2Fcn.bing.com%2F; st_sn=6; st_psi=2024031519150576'
              '9-117001356555-7675512820'
}


def crawl_content(count=1):
    """
    根据 URL 获取内容
    :param count: 页码
    :return: 获取的 HTML 内容
    """
    url = base_url + '/list,waihui.html'
    if count != 1:
        # count != 1 的时候就是指定页数的评价
        url = base_url + '/list,waihui' + f'_{count}' + '.html'
    try:
        print(Fore.BLACK + '-' * 50, '正在获取:' + url)
        response = requests.get(url, headers=headers)
        # 个人经历的判断
        if response.status_code == http.HTTPStatus.PERMANENT_REDIRECT:  # 请求头信息不全可能会触发 redirect 重定向错误
            print('请检查请求头(headers)信息!!')
            # 最后请求的内容也是空直接结束程序
            sys.exit()
        else:
            if response.text.find('<ul class="tab_content"') > 0:
                return response.text
            else:
                print('-' * 50, '获取的:(' + url + ')内容可能不正确!!')
    except urllib.error.URLError as e:
        print('URLError: ', '\n', url, '\n', e.reason)
        sys.exit()


def spider_out_comment(content):
    """
    根据获取的内容解析需要的内容
    :return:
    """
    # with open('1.html', 'r', encoding='utf-8') as file:
    #     content = file.read()
    # 创建 selector 对象读取解析内容
    selector = Selector(text=content)
    list_body = selector.xpath('//li[contains(@class, "defaultlist")]/table[contains(@class, "default_list")]/tbody[c'
                               'ontains(@class, "listbody")]').xpath('.//tr[contains(@class, "listitem")]')
    data = []  # 存储信息
    for item in list_body:
        read_count = item.css('div.read::text').get()  # 阅读量
        reply = item.css('div.reply::text').get()  # 评论数
        title = item.css('div.title > a::text').get()  # 标题
        title_url = item.css('div.title > a').attrib['href']  # 标题对应的链接
        author = item.css('div.author > a::text').get()  # 作者
        author_url = item.css('div.author > a').attrib['href']  # 作者主页
        # 获取更新时间
        update_time = item.xpath('.//div[contains(@class, "update")]/text()').get()
        data.append({
            'id': re.findall('[0-9]+', title_url)[0],
            'read_count': read_count,
            'reply': reply,
            'title': title,
            'title_url': title_url,
            'author': author,
            'author_url': author_url,
            'update_time': update_time
        })
    save_mysql(data)


def save_mysql(data):
    """
    保存信息
    :return:
    """
    cursor = db.cursor()
    print(Fore.BLACK + '-' * 50 + '保存获取的信息')
    count = 0
    for i in range(len(data)):
        keys = ', '.join(data[i].keys())  # 使用变量名作为字段名
        values = ', '.join(['%s'] * len(data[i]))
        # on duplicate key update 当 key 一直的时候不做新增操作,修改
        sql = f'insert into comment ({keys}) values ({values})'
        try:
            cursor.execute(sql, tuple(data[i].values()))
        except pymysql.Error:
            print(Fore.RED, '已经存在了:', data[i]['id'])
            db.rollback()
        else:
            count += 1
            db.commit()
    print(Fore.GREEN + '-' * 50 + '保存成功!共有 ' + str(count) + ' 条')


if __name__ == '__main__':
    for i in range(5):
        spider_out_comment(crawl_content(i + 1))
    db.close()

  • 43
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爬虫探索者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值