SCRAPY获取起点中文网小说免费章节
创建项目
scrapy startproject qidian
cd qidian
scrapy genspider spider qidian.com
需求分析
- 找到要爬取的小说地址
- 发送请求,清洗并存储数据
- 写入本地文件
配置参数
item参数设置
- 书名-name
- 章节名-chapter_name
- 作者-author
- 标签-tag
- 章节内容-text
- 章节内容碎片-text_list
setting参数设置
配置管道PIPELINE
ITEM_PIPELINES
运行日志只输出‘WARNING’级别以上的通知
LOG_LEVEL ='WARNING'
请求页面并存储数据(主程序)
- 确定要爬取的网页范围和起点:
name ='spider'
allowed_domains = ['qidian.com']
start_urls = ['http://qidian.com/']
item = QidianItem()
- 获取要爬取的小说详情页地址
def parse(self, response):
url_list = response.xpath('/html/body/div[1]/div[7]/div[1]/div/ul/li[1]/strong/a/@href').extract()
for urlin url_list:
yield scrapy.Request(
url='https:'+url,
meta={'item': self.item},
callback=self.parse_one
)
- 获取小说信息与小说第一章的地址
def parse_one(self, response):
item = response.meta['item']
item['text'] = []
item['chapter_name'] = []
item['name'] = response.xpath('/html/body/div/div[6]/div[1]/div[2]/h1/em/text()').extract_first()
chapter_list = response.xpath('//*[@id="j-catalogWrap"]/div[2]/div/ul/li/a/@href').extract()
yield scrapy.Request(
url='https:' + chapter_list[0],
meta={'item': self.item},
callback=self.parse_two
)
- 获得每章内容,获取下一章的地址并判断是否VIP页(避免因为多线程导致章节乱序)
def parse_two(self, response):
item = response.meta['item']
item['text_list'] = response.xpath('//*[@class="read-content j_readContent"]/p/text()').extract()
item['chapter_name'].append(response.xpath('//*[@class="j_chapterName"]/span/text()').extract_first())
url = response.xpath('//*[@id="j_chapterNext"]/@href').extract_first()
nextChapterVip = re.findall(r'g_data.nextChapterVip = (\d);', response.text)[0]
nextId = re.findall(r'nextId :(.*?),', response.text)[0]
item['text'].append(' \n\n'.join(item['text_list']))
if nextChapterVip =='0' and nextId !='-1':
yield scrapy.Request(
url='https:' + url,
meta={'item': self.item},
callback=self.parse_two
)
else:
yield item
下载到本地文件
利用管道pipeline完成最后的写入
with open(file='{}.txt'.format(item['name']), mode='a', encoding='utf-8')as f:
for iin range(len(item['chapter_name'])):
f.write(item['chapter_name'][i])
f.write('\n' *2)
f.write(item['text'][i])
f.close()
过程中遇到的问题
- 多线程导致爬取的章节乱序
放弃多线程爬取同一本小说,改为每次爬完一章内容再获取下一章地址,保证内容的存储顺序是正确的 - 相对网址无效
Missing schemein request url
- 手动修改成绝对地址,如在网址前加上域名
- urljoin函数
response.urljoin(url)
练习目标
熟悉html语言与xpath用法
熟悉scrapy参数与各文件的作用
熟悉request与response的形式
熟悉如何从网页源中寻找所需要的文件/地址