用python爬取小说在同步状态下,下载缓慢,所以用asynio/await写了一个异步的爬取(仅用于学习!)
-
获取各章节的网址和题目(从12开始取值是为了过滤掉最新章节对顺序的影响,包括xpath的值,具体需要对网页结构进行分析,不能直接套用)
async def get_link(url):
req = requests.get(url, headers=HEADERS)
req.encoding = 'gbk'
Xpath = parsel.Selector(req.text)
links = Xpath.xpath('/html/body/div[4]/dl/dd/a/@href').extract()
full_links = [BASEURL + link for link in links]
names = Xpath.xpath('/html/body/div[4]/dl/dd/a/text()').extract()
name_list = [name.strip() for name in names]
name_link = zip(full_links[12:], name_list[12:])
async with httpx.AsyncClient() as client:
task = []
for link, name in name_link:
task.append(get_text(client, name, link))
await asyncio.wait(task)
save_text(name_list[12:])
这其中使用httpx异步请求,可以加快访问各章节的速度
然后将各章节任务添加到任务队列中,交由asynio处理
-
各章节任务就是获取章节内容,然后保存即可。但是由于asynio的任务的处理是无序的,所有使用一个字典进行缓存返回内容,在缓存完毕时,将字典内容写入到txt中。
async def get_text(client, name, link):
req = await client.get(link, headers=HEADERS, timeout=None)
html = etree.HTML(req.text)
text = html.xpath('//*[@id="content"]/text()')
await save_text_dic(name, text[:-2])
3.这个地方最好边缓存边写入,类似与生产者消费者,才疏学浅,没有实现思路)
async def save_text_dic(name, texts):
# TODO:边缓存边写入
dic[name] = texts
4.将字典中内容按照爬取的顺序写入即可。
def save_text(name_list):
# 文件目录
path = ""
if not os.path.exists(path):
os.mkdir(path)
#小说名
f = open(f'{path}/小说名.txt', 'a', encoding='utf-8')
# async with open(f"./result/{name}.txt", 'w', encoding="utf-8") as f:
for name in track(name_list):
f.write(name)
f.write('\n\n')
for text in dic[name]:
# print(text)
f.write(text)
f.write('\n\n')
f.write('\n')
5.最后主函数和一些类变量(偷懒没有将所有函数写在类中)
#用于拼接章节网址的基础网址
BASEURL = ""
#字典声明
dic = {}
if __name__ == '__main__':
#具体某本小说的网址
url = ''"
loop = asyncio.get_event_loop()
loop.run_until_complete(get_link(url))
写的很简陋,主要是为了学习一下异步和协程。
与同步下载相比,确实快了许多,但是会偶尔因为httpx的连接超时导致中断,想排查的时候结果成功了==
|