简单的Python爬虫demo

        Python零基础,只是粗略看过一些Python语法视频,有不对或更好的写法欢迎评论区指出。废话不多说直接上代码。

一、项目目录

    const.py   constant.py  常量工具类。main.py 爬虫程序

                

 二、代码

        1.常量类       

        先说一下这个常量类的作用,一开始我的设想是想参考Java项目那样可以把常量单独放到一个文件中,数据库连接单独放到一个文件中,sql语句单独放到一个文件中。但是实际开发中发现代码量其实很小,没必要单独写。对于比较复杂的工程来说可能会有这种需求。这里只尝试了常量类的归类及注册,避免了当有很多常量出现时,不小心重复或者名字不统一的情况。

        const.py

import sys

"""
该类定义了一个方法__setattr()__,和一个异常ConstError, ConstError类继承
自类TypeError. 通过调用类自带的字典__dict__, 判断定义的常量是否包含在字典
中。如果字典中包含此变量,将抛出异常,否则,给新创建的常量赋值。
最后两行代码的作用是把const类注册到sys.modules这个全局字典中。
"""


class _const:
    # 自定义异常处理
    class ConstError(PermissionError):
        pass

    class ConstCaseError(ConstError):
        pass

    # 重写 __setattr__() 方法
    def __setattr__(self, name, value):
        if name in self.__dict__:  # 已包含该常量,不能二次赋值
            raise self.ConstError("Can't change const{0}".format(name))
        if not name.isupper():  # 所有的字母需要大写
            raise self.ConstCaseError("const name{0} is not all uppercase".format(name))
        self.__dict__[name] = value


# 将系统加载的模块列表中的 constant 替换为 _const() 实例
sys.modules[__name__] = _const()

 constant.py

import const

'''
    定义常量:     格式:const.大写英文字母
    const.DEMO = 1
    const.DEMO = 4  # 常量已存在,重复报错ConstError
    conStant.demo = 1  # 常量名字未大写,报错ConstCaseError
'''
# 爬虫信息
const.URL = 'https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=85&provinceId=0&pageSize=1' \
            '&isVerify=1&pageNo=1 '
const.HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                               'Chrome/106.0.0.0 Safari/537.36'}
const.ENCODING_GBK = 'GBK'
const.ENCODING_UTF8 = 'utf-8'

# 数据库信息
const.HOST = 'xxx.xxx.xxx.xxx'
const.USER = 'root'
const.PWD = 'password'
const.PORT = 3306
const.DBNAME = 'dbName'

        2.爬虫程序

import requests
import pymysql
import traceback
import re

from datetime import datetime
from constant import const

'''
    静态页面抓取,找到固定的url,请求抓取网页,然后使用lxml的xpath解析数据
        from lxml import etree
        
        resp = requests.get(url, headers=header,params=params) #括号内参数可选
        ...
        html = etree.HTML(resp.text)
        nums = html.xpath('//div[@class="ball_box01"]/ul/li[@class="ball_red"]/text()')
        遍历nums获取数据
    动态页面抓取,通过开发者工具的Fetch/XHR找到正确的请求,请求获取json,转化为字典,遍历索引获取数据
        resp = requests.get(url, headers=header,params=params) #括号内参数可选
        ...
        dic = resp.json()
'''
# 1.请求网址,获取响应
resp = requests.get(const.URL, headers=const.HEADERS)
resp.encoding = const.ENCODING_UTF8
# 2.解析响应内容,获取需要的数据
dic = resp.json().get('value').get('list')[0]
'''彩票名称'''
lotteryGameName = dic.get('lotteryGameName')
'''开奖时间'''
lotteryDrawTime = dic.get('lotteryDrawTime')
'''开奖期数'''
lotteryDrawNum = dic.get('lotteryDrawNum')
'''开奖结果'''  # re.sub()可传三个参数 第一个要替换的数据,第二个要替换成的数据,第三个是你需要改变的字符串
lotteryDrawResult = re.sub(' ', ',', dic.get('lotteryDrawResult'))
# str.split(sep, maxsplit) sep是分割符,不写表示所有的空字符,包括空格、换行(\n)、制表符(\t)等,maxsplit是分割次数。
lotteryDrawResult_lit = dic.get('lotteryDrawResult').split()
'''出球顺序'''
lotteryUnsortDrawresult = dic.get('lotteryUnsortDrawresult').replace(' ', ',').replace('+', ',')

# 3.连接数据库存储数据
now = datetime.now()
now = now.strftime("%Y-%m-%d %H:%M:%S")
sql = "INSERT INTO `hng`.`lottery_DrawResult`(`lotteryGameType`, `lotteryDrawTime`, `lotteryDrawNum`, " \
           "`lotteryDrawResult`, `lotteryUnsortDrawresult`, `lotteryDrawNum_red1`, `lotteryDrawNum_red2`, " \
           "`lotteryDrawNum_red3`, `lotteryDrawNum_red4`, `lotteryDrawNum_red5`, `lotteryDrawNum_blue1`, " \
           "`lotteryDrawNum_blue2`, `createTime`) " \
           "VALUES " \
           "('%s','%s', '%s','%s', '%s', '%s','%s', '%s', '%s','%s', '%s', '%s', '%s')"
data = (
    lotteryGameName, lotteryDrawTime, lotteryDrawNum, lotteryDrawResult, lotteryUnsortDrawresult,
    lotteryDrawResult_lit[0], lotteryDrawResult_lit[1], lotteryDrawResult_lit[2], lotteryDrawResult_lit[3],
    lotteryDrawResult_lit[4], lotteryDrawResult_lit[5], lotteryDrawResult_lit[6], now)


def main():
    try:
        conn = pymysql.connect(host=const.HOST, user=const.USER, password=const.PWD, port=const.PORT, db=const.DBNAME,
                               charset="utf8")
        print("mysql数据库连接成功,当前数据库版本为: %s" % conn.get_server_info())
        cmd = conn.cursor()
        cmd.execute(sql % data)
        conn.commit()
        print("更新影响的数据行数: %s" % cmd.rowcount)
        print("最后一次增长的ID: %s" % cmd.lastrowid)
    except Exception:
        print("处理异常: " + traceback.format_exc())
    finally:
        conn.close()


if __name__ == "__main__":
    main()

说明:

        关于代码的解释都直接在代码中用注释进行了说明,但后续在部署中发现,代码中虽然是注释的部分或者打印的部分,只有存在中文或者中文字符就可能报字符编码的问题,尤其是使用'''XXX'''这种方式进行注释的时候,还有print('XXX')输出的内容中,这种尽可能不要使用中文及中文字符。部署中报错的解决办法是在Python文件头部添加一行指定编码格式的代码,但并不一定可以成功解决,所以还是尽量不要使用中文,如果想注释或者打印,可以使用英文。


        这里额外上一个代码 historyData.py 这个代码是我用来抓取历史的,和主程序的区别就是 主程序是每次只抓取最新的一条数据,该程序可通过URL中的参数指定抓取一批数据。这不是重点,重点是想说明关于里面的数据库的插入操作

cmd.execute(sql % data)   单次插入,data为元组
cmd.executemany(sql, data_lit)  批量插入,data_lit为元组列表

historyData.py

import requests
import pymysql
import traceback
import re
from datetime import datetime

from constant import const

# 通过指定期数获取数据
url = 'https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=85&provinceId=0&pageSize=30' \
      '&isVerify=1&pageNo=1&startTerm=22123&endTerm=22124'
# 1.请求网址,获取响应
resp = requests.get(url, headers=const.HEADERS)
resp.encoding = const.ENCODING_UTF8

# 2.解析响应内容,获取需要的数据
dic_lit = resp.json().get('value').get('list')

# 3.连接数据库存储数据
now = datetime.now()
now = now.strftime("%Y-%m-%d %H:%M:%S")
sql = "INSERT INTO `hng`.`lottery_DrawResult`(`lotteryGameType`, `lotteryDrawTime`, `lotteryDrawNum`, " \
      "`lotteryDrawResult`, `lotteryUnsortDrawresult`, `lotteryDrawNum_red1`, `lotteryDrawNum_red2`, " \
      "`lotteryDrawNum_red3`, `lotteryDrawNum_red4`, `lotteryDrawNum_red5`, `lotteryDrawNum_blue1`, " \
      "`lotteryDrawNum_blue2`, `createTime`) " \
      "VALUE " \
      "(%s,%s, %s,%s, %s, %s,%s, %s, %s,%s, %s, %s, %s)"
data_lit = []
for dic in dic_lit:
    '''彩票名称'''
    lotteryGameName = dic.get('lotteryGameName')
    '''开奖时间'''
    lotteryDrawTime = dic.get('lotteryDrawTime')
    '''开奖期数'''
    lotteryDrawNum = dic.get('lotteryDrawNum')
    '''开奖结果'''  # re.sub()可传三个参数 第一个要替换的数据,第二个要替换成的数据,第三个是你需要改变的字符串
    lotteryDrawResult = re.sub(' ', ',', dic.get('lotteryDrawResult'))
    # str.split(sep, maxsplit) sep是分割符,不写表示所有的空字符,包括空格、换行(\n)、制表符(\t)等,maxsplit是分割次数。
    lotteryDrawResult_lit = dic.get('lotteryDrawResult').split()
    '''出球顺序'''
    lotteryUnsortDrawresult = dic.get('lotteryUnsortDrawresult').replace(' ', ',').replace('+', ',')
    data = (
               lotteryGameName, lotteryDrawTime, lotteryDrawNum, lotteryDrawResult, lotteryUnsortDrawresult,
               lotteryDrawResult_lit[0], lotteryDrawResult_lit[1], lotteryDrawResult_lit[2], lotteryDrawResult_lit[3],
               lotteryDrawResult_lit[4], lotteryDrawResult_lit[5], lotteryDrawResult_lit[6], now)
    data_lit.append(data)

print(data_lit)
def main():
    try:
        conn = pymysql.connect(host=const.HOST, user=const.USER, password=const.PWD, port=const.PORT, db=const.DBNAME,
                               charset="utf8")
        print("mysql数据库连接成功,当前数据库版本为: %s" % conn.get_server_info())
        cmd = conn.cursor()
        cmd.executemany(sql, data_lit)
        conn.commit()
        print("更新影响的数据行数: %s" % cmd.rowcount)
        print("最后一次增长的ID: %s" % cmd.lastrowid)
    except Exception:
        print("处理异常: " + traceback.format_exc())
    finally:
        conn.close()


if __name__ == "__main__":
    main()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

郝南过

感谢大佬打赏,送你一个么么哒

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

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

打赏作者

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

抵扣说明:

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

余额充值