爬虫-异步抓取一部小说

一、利用requests请求同步和aiohttp异步,两个结合来获取小说里的内容

1、先利用cookie和session来实现登录

  • 根据post请求,带入参数来建立会话,并获取session
  • 利用session来进行同步请求获取,每一章节的名称和链接地址

 通过上面的图,发现在/html/body/div[5]/dl/dd范围内的a标签里面存放着小说章节名称和链接地址,点击章节的地址就可以跳转到对应的章节页面,所以可以使用xpath来通过a标签来获取章节名称和URL地址

又因为章节名和URL地址的网络请求只有一个,或者说只有请求到章节名称和链接才能获取每章节的内容,所有可以直接用requests同步请求的方式来获取,牵涉到登录问题,用seesion来请求,如下

if __name__ == '__main__':
    # 建立session会话
    session = requests.Session()
    hearder = {
        "User - Agent":
         "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    }
    data = {
        "loginName": "13xxxxxxxxx",
        "password": "zpxxxxx"
    }
    # 1、登录:(这里的浏览器必须是login登录按钮的链接)
    url = "https://passport.17k.com/ck/user/login"
    # 2、可以用F12检查浏览器的请求情况:可以找到cookie  把请求和cookie带进去 post还是get可以在浏览器中看到
    session.post(url=url, data=data)
    # 3、用sesion请求获取
    time.sleep(1)
    chapter_list = "https://www.17k.com/list/3378901.html"
#获取的章节名和URL链接的网络请求只有一个,直接使用requests请求库发送同步请求
async def get_link(chapter_list,session):
    response = session.get(chapter_list)
    response.encoding = 'utf-8'
    Xpath = etree.HTML(response.text)
    a_list = Xpath.xpath('/html/body/div[5]/dl/dd/a')
    for a in a_list:
        # #获取每章节的url链接
        links = a.xpath('./@href')
        linklist = ['https://www.17k.com/' + link for link in links]
        ##获取每章节的名字
        names = xpath('./span/text()')
        namelist = [name for name in names]
        # namelist = [names.replace('\n', '').replace('\t', '') for name in names]
        # 将名字和url链接合并成一个元组
        name_link_list = zip(namelist,linklist)
        #获取到URL链接和章节名后,需要构造一个task任务列表来作为异步协程的可等待对象
        task = []
        for name ,link in name_link_list:
            task.append(get_text())

获取每章节的小说内容:

async def get_text(name,link):
    async with aiohttp.ClientSession()as session:
        async with session.get(url= link) as response:
            html = await response.text()
            text = html.xpath('//*[@id="readArea"]/div[1]/div[2]/p/text()')
            await save_data(name,link)

将上一步获取到的章节名和URL链接传到async声明定义的get_text()方法中,使用with块来使用aiohttp.ClientSession()方法发送异步请求,其中:

aiohttp.ClientSession() as session <------->相当于requests赋给session,说session相当于requests;发送网络请求、传入的参数、返回响应内容都和requests请求库大同小异,只是aiohttp请求库需要用async和await进行声明,将获取到的小说内容和章节名传入到定义的save_data()中

 

保存小说到文本中,异步需要用async来声明,

async def save_data(name,text):
f=open(f'小说/{name}.text','w',encoding='utf-8')
for texts in text:
f.write(texts)
f.write('\n')
print(f'正在爬取{name}')

最后调用asyncio.get_event_loop()方法进入事件循环,再调用loop.run_until_complete(get_link())方法运行事件循环,直到get_link()方法运行结束。

    loop = asyncio.get_event_loop()
    loop.run_until_complete(get_link(chapter_list,session))

文档参照来自https://zhuanlan.zhihu.com/p/416279762

posted @ 2024-01-26 21:36  zhang0513  阅读(16)  评论(0编辑  收藏  举报