本帖最后由 FeiyuYip 于 2021-5-8 13:49 编辑
最近在自学Python,用的教材是李宁老师的《Python爬虫技术 深入理解原理、技术与开发》,这篇讲到“项目实战:抓取起点中文网的小说信息”,昨晚跟着代码走了一遍,今天又按照自己的理解默写了一遍,作了一些改动,均成功了。
下面讲一下大概的思路,基本是照本宣科,有这本书的同学可以参照这本书来阅读。
一、网址的确定
通过翻页,发现网址变化规律为:“https://www.qidian.com/all?page=页码”,好像只有5页,所以用的是range(1,6),故每页的代码可以写为:
for i in range(1, 6):
url = 'https://www.qidian.com/all?page=' + str(i) # i用str转为字符形式
二、通过requests抓取小说页面,这本书中介绍了urllib、urllib3、requests三种不同的方法,每种方法表现形式有点不同,这里用requests。设置一个函数叫getOnePage(),通过传入刚刚的网址,得到网页的内容:
def getOnePage(url):
try:
req = requests.get(url=url, headers=headers)
if req.status_code == 200:
return req.text # 注意要返回text
return None
except Exception:
return None
三、分析网页代码信息,得到想要的内容
使用的是lxml解析库和xpath解析方式,设置的函数名为parseOnePage()
1.首先读取网页代码内容
from lxml import etree
def parseOnePage(html):
items = etree.HTML(html)
2.然后查看网页,确定需要抓取的信息:1标题、2作者、3类型、4连载情况(完成度)、5简介,以及6小说链接(图中看不到)
通过快捷键F12来到开发者工具,在"Elements"选项卡查看各个信息所在的位置。可以通过开发者工具左上角的箭头来定位。
3.通过上图,可以发现所有的关键信息都是在'<ul class="all-img-list cf">'节点下的<li>节点当中,所以使用xpath方法来获取到这个节点的信息。
infos = items.xpath('//ul[@class="all-img-list cf"]/li')
4.然后再来分别获取标题、作者、类型、完成度、简介、链接所在位置的信息,放入yield生成器中。注意类型由两部分组成,需要拼合一下,获得的链接缺少了"https:",所以也要加上。
for info in infos:
style_1 = info.xpath('div[2]/p[1]/a[2]/text()')[0]
style_2 = info.xpath('div[2]/p[1]/a[2]/text()')[0]
yield {
'title': info.xpath('div[2]/h4/a/text()')[0],
'author': info.xpath('div[2]/p[1]/a[1]/text()')[0],
'style': style_1 + '·' + style_2,
'complete': info.xpath('div[2]/p[1]/span/text()')[0],
'introduce': info.xpath('div[2]/p[2]/text()')[0].strip(),
'address': 'https:' + info.xpath('div[2]/h4/a/@href')[0]
}
四、将抓取的数据保存到novels.txt文件中,使用save()函数
import json
def save(content):
with open('novels.txt', 'a+', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n')
五、将抓取到的数据保存到表格中
需要用到的是xlwt,它通常的用法是
import xlwt
book.Workbook(encoding='utf-8') # 创建Workbook对象,编码为utf-8
sheet = book.add_sheet('Sheet') # 为book添加一个Sheet,这个就是表格内的一页一页的标签页,如果添加多个类似。'Sheet'为标签的名字
sheet.write(i, j, content)# 在sheet内写入内容,i、j分别为行、列,起始值为0
book.save('book.xls') # 将book保存,文件名为book.xls
首先是创建一个表头,表头的列包括:序号、标题、作者、类型、完成度、简介、链接
header = ['序号', '标题', '作者', '类型', '完成度', '简介', '链接']
book = xlwt.Workbook(encoding='utf-8')
sheet = book.add_sheet('起点小说抓取')
for h in range(0, len(header)):
# 第0行第h列依次写入header的每个信息
sheet.write(0, h, header[h])
表头制作好了,然后每一行填入一个小说的相应信息,代码为:
import time
# j表示行数,起始为1
j = 1
novels = parseOnePage(html)
for novel in novels:
# t为了方便在打印时显示第一个小说,则把j也打印出来
print(j, novel)
# 表格内写入数据,分别是第j行的0-6列写入序号、标题、作者、类型、完成度、简介、链接,与表头对应。。
sheet.write(j, 0, j)
sheet.write(j, 1, novel['title'])
sheet.write(j, 2, novel['author'])
sheet.write(j, 3, novel['style'])
sheet.write(j, 4, novel['complete'])
sheet.write(j, 5, novel['introduce'])
sheet.write(j, 6, novel['address'])
j += 1
time.sleep(0.2)
六、大部分内容已经照书分析完了,接下来就是完整的代码了。毕竟分模块分析时,在某些调用或者迭代的地方不太好讲清楚,这时候就要结合完整的代码来阅读理解了。
import requests
from lxml import etree
import xlwt
import json
import time
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
}
def getOnePage(url):
try:
req = requests.get(url=url, headers=headers)
if req.status_code == 200:
return req.text # 注意要返回text
return None
except Exception:
return None
def parseOnePage(html):
items = etree.HTML(html)
infos = items.xpath('//ul[@class="all-img-list cf"]/li')
for info in infos:
style_1 = info.xpath('div[2]/p[1]/a[2]/text()')[0]
style_2 = info.xpath('div[2]/p[1]/a[2]/text()')[0]
yield {
'title': info.xpath('div[2]/h4/a/text()')[0],
'author': info.xpath('div[2]/p[1]/a[1]/text()')[0],
'style': style_1 + '·' + style_2,
'complete': info.xpath('div[2]/p[1]/span/text()')[0],
'introduce': info.xpath('div[2]/p[2]/text()')[0].strip(),
'address': 'https:' + info.xpath('div[2]/h4/a/@href')[0]
}
# 保存文件
def save(content):
with open('novels.txt', 'a+', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n')
if __name__ == '__main__':
# 制作表头,第0行
header = ['序号', '标题', '作者', '类型', '完成度', '简介', '链接']
book = xlwt.Workbook(encoding='utf-8')
sheet = book.add_sheet('起点小说抓取')
for h in range(0, len(header)):
sheet.write(0, h, header[h])
# j为表格内容的行数,起始为1(第0行为上面的表头)
j = 1
# 抓取5页的内容
for i in range(1, 6):
url = 'https://www.qidian.com/all?page=' + str(i) # i用str转为字符形式
html = getOnePage(url)
novels = parseOnePage(html)
for novel in novels:
print(j, novel)
save(novel)
# 表格内写入数据,分别是第j行的0-6列写入序号、标题、作者、类型、完成度、简介、链接,与表头对应。。
sheet.write(j, 0, j)
sheet.write(j, 1, novel['title'])
sheet.write(j, 2, novel['author'])
sheet.write(j, 3, novel['style'])
sheet.write(j, 4, novel['complete'])
sheet.write(j, 5, novel['introduce'])
sheet.write(j, 6, novel['address'])
j += 1
time.sleep(0.2)
# 保存表格
book.save('起点小说抓取.xls')
七、结语
由于也是在自学当中,目前仍有好多知识不理解,包括此文中许多表述不准确甚至错误。这一个实战其实蛮简单的,但写一个帖子下来,也费了几个小时,好处在于,真正地加深了印象,也尝试了md的使用(虽然排版效果还是比较感人)。希望大家都在学习的过程中越走越远。共勉!
八、运行附图
1.打印界面运行图
2.保存的txt文档内容截图
3.保存的xls表格内容截图(格式有调整)
|