目标站点分析
懒人听书-https://www.lrts.me/index,进入主页以后搜索黑暗森林,找到对应资源点击进入黑暗森林
可以看到,url中跟的29320是该资源对应的id,如果要爬其他资源,对应的更改这个id就好了,点击第一集后跳到下面的页面并开始播放
中途做了部分测试,发现上图中的资源其实是通过ajax请求的。如果我们把js禁用,页面就会发生变化,没有数据,如下:
该请求通过控制台可以查看,ttps://www.lrts.me/ajax/playlist/2/29320/1,该请求返回的数据中就包含了mp3资源链接
有了以上的分析,下面就可以使用scrapy爬取数据了
使用scrapy爬取数据
spider的思路是先获取资源总数,懒人听书默认分页是10页,然后计算有多少页,根据页数通过上面分析的异步url去请求包含mp3资源的页面。然后使用pipeline去下载即可。代码就比较简单了
spider
class SantiSpider(scrapy.Spider):
name = 'santi'
allowed_domains = ['www.lrts.me']
start_urls = ['https://www.lrts.me/book/29320/']
# start_urls = ['https://www.lrts.me/ajax/playlist/2/29320/1']
def parse(self, response):
total_count = response.xpath('/html/body/div[1]/div[1]/section[1]/div[2]/ul[3]/li[1]/text()').extract_first()
total_page = (int(total_count) // 10) + 1 if total_count else 0
base_download_url = 'https://www.lrts.me/ajax/playlist/2/29320/{}'
for page in range(total_page):
start = page * 10 + 1
url = base_download_url.format(start)
yield scrapy.Request(url=url, callback=self.parse_download)
def parse_download(self, response):
lis = response.css('.section li')
for li in lis:
item = SantiItem()
res_url = li.css('div.column1.nowrap > input[type="hidden"]:nth-child(3)::attr(value)').extract_first()
item['file_urls'] = [res_url]
res_num = li.css('div.column1.nowrap > div > span::text').extract_first()
item['res_num'] = res_num
yield item
item
class SantiItem(scrapy.Item):
file_urls = scrapy.Field()
total_count = scrapy.Field()
res_num = scrapy.Field()
pipeline
因为要改文件名,所以使用自定义的pipeline,重写file_path方法
class MyfilesPipeline(FilesPipeline):
def get_media_requests(self, item, info):
for url in item["file_urls"]:
yield scrapy.Request(url,meta={'item':item})
def file_path(self, request, response=None, info=None):
return '三体2黑暗森林_第'+request.meta['item']['res_num']+'集.mp3'