大家好呀,空虚且漫长的三天小长假终于过去了,,哈哈哈哈,又是一个愉快的周一
刚到公司还没坐下,我旁边的IOS同学就悄悄告诉我项目出了BUG,并给我投来了一个神秘的微笑。。。
在我吃完早餐,喝完开水,上完厕所之后,手终于没那么抖了,慢慢的打开电脑,才发现只是一个小问题。哈哈哈哈,花费一分钟解决。哎哟,可把我牛逼坏了
旁边的IOS同学凑过来,用他那不太飘准的普通发给我说:“兄die,上次那个爬图片的很好用啊,不过我这几天看图片看太多了,灵感倒是有很多,就是身体有点吃不消。最近迷上了看小说,可是正版的冲不起钱,盗版的广告又太多,你给我解决解决?”
我:“作为一个优雅的社畜,怎么能看盗版呢?朕瞧不起你这无耻之徒。发过来,朕先举报(保存)一手”
半小时后,IOS同学:“兄die,怎么样了,解决了吗”
我心想:卧槽,看入迷了,还没开始写,怎么办。
表面稳如老狗,答曰:“emmmmm,这个比较有技术难度,稍等一下,就快好了”
当然,小说要看,问题还是要解决。怎么才能只看自己想看的内容,去掉自己不想看的内容呢?心念电转,还是用爬虫吧,内容都拿下来,只保存自己想看的不就行了。说干就干。。。
书名《全职法师》,url在代码里
页面大概长这样:
爬虫三连:获取网页,解析网页,保存目标
随手写个第一版,将内容保存在文件里面,以title做文件名:
import queue
import requests
from lxml import etree as et
import re
import random
import time
import os
# 请求头
headers = {
# 用户代理
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
USER_AGENT_LIST = [
'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'
]
# 保存小说文件
def save_file(dir,filename,content):
# 如果目录不存在,则新建
if not os.path.exists(dir):
os.makedirs(dir)
save_dir = dir+'/'+filename+'.txt'
#注意:win系统默认新文件编码格式gbk,这里需指定utf-8编码
with open(save_dir, 'w',encoding='utf-8') as f:
f.write(content)
print('ok')
def get_chapter_url(list_url, base_url, queue):
# 获取页面信息
response = requests.get(url=list_url, headers=headers)
# 获取请求状态码
code = response.status_code
if code == 200:
html = et.HTML(response.content)
# 获取该小说章节list
chapter_url = html.xpath('//*[@id="list"]/dl/dd/a/@href')[9:40]
k = 1
for i in chapter_url:
#组装小说章节url
page_url = base_url + i
#将小说章节url+章节编号入队
queue_element = page_url, str(k)
queue.put(queue_element)
k = k + 1
def get_detail_html(queue):
while not queue.empty():
#休息一下,太快会503.等待时长可根据实际情况调节,你可以在503的边缘疯狂试探
time_num = 5
time.sleep(time_num)
# Queue队列的get方法用于从队列中提取元素
queue_element = queue.get()
queue.task_done()
# 获取章节url
page_url = queue_element[0]
# 获取章节编号
chapter_num = queue_element[1]
headers = {
# 从代理列表随机获取代理
'User-Agent': random.choice(USER_AGENT_LIST)
}
response = requests.get(url=page_url, headers=headers)
response.encoding = "utf-8"
# 请求状态码
code = response.status_code
if code == 200:
html = et.HTML(response.content)
# 获取该章小说title
title = html.xpath('//h1/text()')[0]
# 获取该章小说内容
r = html.xpath('//*[@id="content"]/text()')
content = ''
for i in r:
# 正则匹配,去除干扰字符,只保留汉字和数字
#\u标识unicode编码,u不能大写;之后跟一个十六进制,表示相应字符对应的unicode值,十六进制中英文不区分大小写
#data = re.sub(u"([^\u4E00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])","",i)
content = content + i
# 去除两端空格
title = title.strip()
content = content.strip()
#保存文件
save_file(save_dir, title, content)
else:
print(code)
print(title)
# 主函数
if __name__ == "__main__":
# 小说章节基地址
base_url = 'https://www.biqugecom.com'
# 小说章节列表页地址
list_url = 'https://www.biqugecom.com/0/15/'
#文件保存目录,自由设置,开心就好a
save_dir = os.path.abspath('../quanzhifashi/')
# 用Queue构造一个先进先出队列
urls_queue = queue.Queue()
#获取章节url列表
get_chapter_url(list_url,base_url,urls_queue)
#获取章节内容,存入数据库
get_detail_html(urls_queue)
print('the end!')
略一运行:
保存下来的小说:
过了一会儿,IOS:“老哥,你这个txt让我很为难啊,用户体验不怎么的,优化一下?”
沉思五秒后,我:“那我给你写成接口,你自己随便写一个APP,调我的接口怎么样?这样的话,界面你可以自己DIY,还能根据你的内裤颜色换小说背景色。”
IOS:“这个好,这个好,虽然我不怎么穿内裤,嘿嘿”
我:“。。。。。。。。。。。”
niubi要吹,代码还是要写。数据库那么多,选什么牌子呢?数据库技术哪家强,mysql数据库帮你忙,好用开源是真香
先安装一个mysql驱动吧:pip3 install mysql-connector
建个表保存小说章节编号,title和正文内容:
# Host: localhost (Version: 5.7.26)
# Date: 2020-01-06 11:28:42
# Generator: MySQL-Front 5.3 (Build 4.234)
/*!40101 SET NAMES utf8 */;
#
# Structure for table "novel"
#
DROP TABLE IF EXISTS `novel`;
CREATE TABLE `novel` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`chapter_num` int(11) DEFAULT NULL COMMENT '章节编号',
`title` varchar(20) NOT NULL DEFAULT '0' COMMENT '章节标题',
`content` varchar(15000) DEFAULT NULL COMMENT '章节内容',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=112 DEFAULT CHARSET=utf8;
然后写个方法存数据,抱着试一试的心态,点击运行,得如下结果:
打开mysql一看。
呵,我可真是天选之子
完整代码:
import queue
import requests
from lxml import etree as et
import re
import random
import time
import os
import mysql.connector
# 请求头
headers = {
# 用户代理
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
#用户代理列表
USER_AGENT_LIST = [
'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'
]
# 保存小说文件
def save_file(dir,filename,content):
# 如果目录不存在,则新建
if not os.path.exists(dir):
os.makedirs(dir)
save_dir = dir+'/'+filename+'.txt'
#注意:win系统默认新文件编码格式gbk,这里需指定utf-8编码
with open(save_dir, 'w',encoding='utf-8') as f:
f.write(content)
print('ok')
# 插入数据库
def insert_data(chapter_num, title, content):
conn = mysql.connector.connect(user='root', password='root', database='test')
cursor = conn.cursor()
try:
cursor.execute('insert into novel (chapter_num, title, content) values (%s, %s, %s)', [chapter_num, title, content])
conn.commit()
except Exception as e:
print('Error:', e)
finally:
cursor.close()
conn.close()
def get_chapter_url(list_url, base_url, queue):
# 获取页面信息
response = requests.get(url=list_url, headers=headers)
# 获取请求状态码
code = response.status_code
if code == 200:
html = et.HTML(response.content)
# 获取该小说章节list
chapter_url = html.xpath('//*[@id="list"]/dl/dd/a/@href')[9:40]
k = 1
for i in chapter_url:
#组装小说章节url
page_url = base_url + i
#将小说章节url+章节编号入队
queue_element = page_url, str(k)
queue.put(queue_element)
k = k + 1
#获取章节内容,存入数据库
def get_detail_html(queue):
while not queue.empty():
#休息一下,太快会503.等待时长可根据实际情况调节,你可以在503的边缘疯狂试探
time_num = 5
time.sleep(time_num)
# Queue队列的get方法用于从队列中提取元素
queue_element = queue.get()
queue.task_done()
# 获取章节url
page_url = queue_element[0]
# 获取章节编号
chapter_num = queue_element[1]
headers = {
# 从代理列表随机获取代理
'User-Agent': random.choice(USER_AGENT_LIST)
}
response = requests.get(url=page_url, headers=headers)
response.encoding = "utf-8"
# 请求状态码
code = response.status_code
if code == 200:
html = et.HTML(response.content)
# 获取该章小说title
title = html.xpath('//h1/text()')[0]
# 获取该章小说内容
r = html.xpath('//*[@id="content"]/text()')
content = ''
for i in r:
content = content + i
# 去除两端空格
title = title.strip()
content = content.strip()
#插入数据库
insert_data(chapter_num, title, content)
#保存文件
#save_file(save_dir, title, content)
else:
print(code)
print(title)
# 主函数
if __name__ == "__main__":
# 小说章节基地址
base_url = 'https://www.biqugecom.com'
# 小说章节列表页地址
list_url = 'https://www.biqugecom.com/0/15/'
#文件保存目录,自由设置,开心就好a
save_dir = os.path.abspath('../quanzhifashi/')
# 用Queue构造一个先进先出队列
urls_queue = queue.Queue()
#获取章节url列表
get_chapter_url(list_url,base_url,urls_queue)
#获取章节内容,存入数据库
get_detail_html(urls_queue)
print('the end!')
又过了一会儿,IOS同学:“兄die,你这个有点慢啊,下载一章还要休息几秒”
我:“因为这个网站有限制,太快了会503,再说就算你一目十行也看不了那么快吧”
IOS:“看小说倒是不影响,就是你这样的代码影响我吹牛逼”
我:“emmmmm,那我搭建个IP池,然后给你改成多线程”
当朕准备搭建IP池的时候,产品经理的头像突然闪了起来。
只见消息列表里面躺着一个需求文档,并附文:
emmmmmm,溜了溜了。
The end !
学到了就要教人,赚到了就要给人
薪火相传,方能生生不息