爬虫学习笔记四、 python爬虫实战,爬取图书馆资料,存储到mysql数据库

时间:2022-09-18 17:34:01



1、设置url

进入图书馆书目检索系统,分析它的url,可以很容易找到规律就是它的后缀no=0000+五位的图书编码,例如:http://210.44.58.116:8080/opac/item.php?marc_no=0000560645 

利用规律我们就可以这样来遍历url,代码如下:

def geturl(start):  
#start为开始的图书编码
url='http://210.44.58.116:8080/opac/item.php?marc_no=0000'
for i in range(start,600000):
a="%06d"%i
url1=url+str(a)

2、分析页面源码,筛选需要获取的数据,编写正则表达式(以书名为例)

     打开页面源码,找到题名所在的位置,如下:

<dt>题名/责任者:</dt>
<dt>题名/责任者:</dt>
<dd><a href="openlink.php?title=Python%E5%92%8CHDF5%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%BA%94%E7%94%A8">&#x0050;&#x0079;&#x0074;&#x0068;&#x006f;&#x006e;&#x548c;&#x0048;&#x0044;&#x0046;&#x0035;&#x5927;&#x6570;&#x636e;&#x5e94;&#x7528;</a>/&#x0028;&#x7f8e;&#x0029;&#x0020;&#x0041;&#x006e;&#x0064;&#x0072;&#x0065;&#x0077;&#x0020;&#x0043;&#x006f;&#x006c;&#x006c;&#x0065;&#x0074;&#x0074;&#x0065;&#x8457; &#x80e1;&#x4e16;&#x6770;&#x8bd1;</dd>

通过页面分析到,unicode乱码的部分&#x0050;&#x0079;&#x0074;&#x0068;&#x006f;&#x006e;&#x548c;&#x0048;&#x0044;&#x0046;&#x0035;&#x5927;&#x6570;&#x636e;&#x5e94;&#x7528;
为我们需要的书名

爬取书名的代码如下:

def getdb(url,i):  
html=urllib.request.urlopen(url).read().decode('utf-8')
try:
#书名
name = re.compile('<dd><a href="openlink.php\?title=(.*?)>(.*?)</a>').findall(html)
name = str_jiequ(name[0][1])
print(url)
except TypeError:
print("失败,本地址下没有信息!")
except IndexError:
print("部分信息获取失败!")
except Exception as e:
print("错误" + e)


因为有乱码存在所以我们需要乱码处理模块,代码如下:

def str_jiequ(s):  
b=''
for i in range(0,int(len(s)/8)):
a=str((bytes(r'\u'+s[(3+i*8):(7+i*8)],'ascii')).decode('unicode_escape'))
b=b+a
return b


3、连接mysql,添加到mysql数据库

def db( name):  
name=str(name)
try:
# 获取数据库连接
conn = pymysql.connect(host='localhost', user='root', password='root', db='pythonDB', port=3306, charset='utf8')
cur = conn.cursor() # 获取一个游标
sql = " INSERT INTO library ( t_name ) VALUES (%s );"
cur.execute(sql, (name))
conn.commit()
cur.close() # 释放游标
conn.close() # 释放资源
except Exception as e:
print("异常" + e)

4、完善代码,实现爬取书名、作者、学科主题、分类号的功能
完整代码如下

import pymysql
import urllib.request
import re

def db( name,author,keyword,coden,i):
name=str(name)
author=str(author)
keyword=str(keyword)
coden=str(coden)
try:
# 获取数据库连接
conn = pymysql.connect(host='localhost', user='root', password='root', db='pythonDB', port=3306, charset='utf8')
cur = conn.cursor() # 获取一个游标
sql = " INSERT INTO library ( t_name , t_automer , t_keyword , t_coden ,t_num ) VALUES (%s,%s,%s,%s,%s);"
cur.execute(sql, (name, author, keyword, coden,i))
conn.commit()
#成功添加打印输出结果
print("成功添加第" + str(i) + "条图书 ------ 书名:" + name + ' 作者:' + author + " 学科:" + keyword + " 编号:" + coden + " 图书序列:" + str(i))
cur.close() # 释放游标
conn.close() # 释放资源
except Exception as e:
print("异常" + e)
geturl(i + 1)
#格式化unicode字符串为中文
def str_jiequ(s):
b=''
for i in range(0,int(len(s)/8)):
a=str((bytes(r'\u'+s[(3+i*8):(7+i*8)],'ascii')).decode('unicode_escape'))
b=b+a
return b
def getData(url,i):
try:
html = urllib.request.urlopen(url).read().decode('utf-8')
#书名
name = re.compile('<dd><a href="openlink.php\?title=(.*?)>(.*?)</a>').findall(html)
name = str_jiequ(name[0][1])
#作者
author = re.compile('<dd><a href="openlink.php\?author=(.*?)>(.*?)</a>').findall(html)
author = str_jiequ(author[0][1])
#学科主题
keyword = re.compile('<dd><a href="openlink.php\?keyword=(.*?)>(.*?)</a>').findall(html)
keyword = str_jiequ(keyword[0][1])
#中途法分类号
coden= re.compile('<dd><a href="openlink.php\?coden=(.*?)>(.*?)</a>').findall(html)
coden = str_jiequ(coden[0][1])
#链接数据库,并将数据添加到数据库中
db(name, author, keyword, coden,i)
except IndexError:
print("部分信息获取失败!")
geturl(i + 1)
except Exception as e:
print("错误" + e)
geturl(i + 1)

def geturl(start):#start为开始的添加的第一个地址
url='http://210.44.58.116:8080/opac/item.php?marc_no=0000'
for i in range(start,600000):
#设置为六位数字前面用零补全
a="%06d"%i
a=str(a)
#将后缀添加到url后
url1=url+a
print(url)#打印url
getData(url1,i)
geturl(0)


运行结果:

爬虫学习笔记四、 python爬虫实战,爬取图书馆资料,存储到mysql数据库

查看数据库:

爬虫学习笔记四、 python爬虫实战,爬取图书馆资料,存储到mysql数据库

存在问题:
1、数据量比较大,六十万条信息,爬取速度太慢,使用多线程+异步+分布式应该会解决
2、正则表达式写的不够好,没有找到其他更好的办法,
3、有些数据爬取失败,具体原因还没去找

4、在爬取数据量很大的时候,可能会出现堆栈溢出,分析原因可能是正则表达式采用的大量递归算法所致,暂时没有找到合理的解决方案

5、有些时候会出现远程服务器断开连接的情况



11/22更新:

上面写的程序会出现堆栈溢出问题,之前以为是因为正则的原因,后来好好看了一下是递归调用geturl(I+1)造成的,经过修改后经一万条信息爬取测试后没有出现问题,修改后的代码如下:\


import pymysql
import urllib.request
import re

def db( name,author,keyword,coden,i):
name=str(name)
author=str(author)
keyword=str(keyword)
coden=str(coden)

try:
# 获取数据库连接
conn = pymysql.connect(host='localhost', user='root', password='root', db='pythonDB', port=3306, charset='utf8')
cur = conn.cursor() # 获取一个游标
sql = " INSERT INTO library ( t_name , t_automer , t_keyword , t_coden ,t_num ) VALUES (%s,%s,%s,%s,%s);"
cur.execute(sql, (name, author, keyword, coden,i))
conn.commit()
print("成功添加第" + str(i) +"条图书 ------ 书名:" + name +' 作者:' + author + " 学科:" + keyword + " 编号:" + coden+" 图书序列:"+str(i))
except Exception as e:
print("异常:" + e)
finally:
cur.close() # 释放游标
conn.close() # 释放资源
def str_jiequ(s):
b=''
for i in range(0,int(len(s)/8)):
a=str((bytes(r'\u'+s[(3+i*8):(7+i*8)],'ascii')).decode('unicode_escape'))
b=b+a
return b
def getdb(url,i):
html = urllib.request.urlopen(url).read().decode('utf-8')
#书名
name = re.compile('<dd><a href="openlink.php\?title=(.*?)>(.*?)</a>').findall(html)
name = str_jiequ(name[0][1])
#作者
author = re.compile('<dd><a href="openlink.php\?author=(.*?)>(.*?)</a>').findall(html)
author = str_jiequ(author[0][1])
#学科主题
keyword = re.compile('<dd><a href="openlink.php\?keyword=(.*?)>(.*?)</a>').findall(html)
keyword = str_jiequ(keyword[0][1])
#中途法分类号
coden= re.compile('<dd><a href="openlink.php\?coden=(.*?)>(.*?)</a>').findall(html)
coden = str_jiequ(coden[0][1])
db(name, author, keyword, coden,i)

def geturl(start):
url='http://210.44.88.116:8080/opac/item.php?marc_no=0000'
i=start
while i<100000:
try:
a="%06d"%i
a=str(a)
url1=url+a
print(url1)
getdb(url1,i)
except Exception as e:
print("部分信息获取失败!")
finally:
i+=1
geturl(0)

昨晚跑了几个小时,测试结果:

1、爬了323K条数据后服务器无法访问了,测试更换ip也不能访问,应该是服务器那边这么多的访问量出现了问题,可能是数据库溢出了。

2、没有再次出现堆栈溢出的错误,更新的版本应该是没问题了,其他错误也没出现。


准备开始学习进程线程方面的知识,试试多线程多进程并发执行的效果,不过对于这个网站还行,对于别的做的安全性比较好的网站,在短时间内大量访问的时候会被检测到而禁封Ip,可以使用ip代理来解决。