需要爬取http://cffex.com.cn/ccpm/?productid=IF页面上的IF、IC、IH、TS、TF、T的持仓信息,时间为[2016.1.1到2020.1.1)。
首先查看robots.txt,该网站没有robots.txt文件。
查看网页源码,发现查询选取日期种类部分使用了
多次写代码,问题主要有:
1.日期部分逻辑小问题;
2.每个页面耗时渐渐增加,爬到一半甚至一个页面需要9s左右,从爬取完到存入库;
3.xml文件中的标签名大小写不一致;标签内容有空格等。
问题1经过几次实验改进。问题2,主要是查重,当表中数据多起来,查重十分费时,而且有时查表太久还会断开连接。问题3,html解析时不区分大小写,入库前对数据去空格。
为了解决问题2,参考了https://www.cnblogs.com/gl1573/p/10129382.html中的超时重试,但最后决定还是先把xml文件存到本地,然后慢慢存入库,对网站的压力小,也不容易中断;另外,由于查重太费时,xml数据中应该没有重复的项目,所以后面改为了直接存入。
爬取内容代码:
import requests
from requests.adapters import HTTPAdapter
from bs4 import BeautifulSoup
import time
import random
import pymysql
import re
def leapYear(year):
# 如果year是闰年则返回True
if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):
return True
return False
def nextDate(date):
# 根据参数date给出下一个日期。date为int列表,格式为年月日星期,如[2020,9,16,3]
y, m, d, w = date
w = (w + 1) % 7
if w == 0:
w = 7
d += 1
if d == 32:
d = 1
m += 1
if m == 13:
m = 1
y += 1
elif d == 31:
if m in {
4, 6, 9, 11}:
d = 1
m += 1
elif d == 30 and m == 2:
d = 1
m = 3
elif d == 29 and m == 2:
if not leapYear(y):
d = 1
m = 3
return [y, m, d, w]
# 1,3,5,7,8,10,12 31
# 4,6,9,11 30
# 2 28/29
def checkDate(date):
#如果没有 星期,则根据 标准日期 找出星期
if len(date) == 3:
standard = [1970, 1, 1, 4]
y, m, d, w = standard
yd, md, dd = date
while y != yd or m != md or d != dd:
standard = nextDate(standard)
y, m, d, w = standard
return standard
return date
def getInput():
# 接受两个表示日期的列表,返回开始日期,结束日期,日期之差(需要爬取的天数),需要的种类
print('请输入开始日期和结束日期,顺序随便。爬取数据包括开始日期但不包括结束日期。\n日期的格式为 年.月.日')
s = input('开始日期:')
e = input('结束日期:')
ks = input('请输入需要的种类,如IF.IC.IH.TS.TF.T,大小写随意。如果需要多个,用.隔开:').upper()
s = s.split('.')
e = e.split('.')
kinds = ks.split('.')
s = checkDate([int(s[0]), int(s[1]), int(s[2])])
e = checkDate([int(e[0]), int(e[1]), int(e[2])])
if s[0] > e[0]:
s, e = e, s
elif (s[0] == e[0]