线程池爬取小说实例

线程池: 一次性开辟一些线程,我们用户直接给线程池提交任务,线程任务的调度交给线程池来完成

针对使用requests请求返回结果为html类型的网站,我最喜欢使用xpath选择,也就是把返回来的html或者xml文档提交给etree.HTML。
当然,你还可以通过python自带的re库来使用正则表达式提取html文档中你所需要的关键字。
还有一种办法是使用bs4包中的BeautifulSoup方法,同样也可以提取到相关的内容。

关键代码如下所示:

'''
使用多线程下载一篇478.7万小说
'''
def get_down_url(url):
    html = etree.HTML(requests.get(url).text)
    filename = html.xpath('/html/body/div[3]/div[1]/h1/text()')[0]
    if not os.path.exists(filename):
        os.mkdir(filename)
    # 获取所有的div
    div_list = html.xpath('/html/body/div[3]/div[2]/div[2]/div')
    # 使用线程池下载
    with ThreadPoolExecutor(1000) as t:
        for child_list in div_list:
            # 获取每个div的名字,方便给文件夹命名
            child_filename = child_list.xpath('./div/text()')[3].replace(' ', '_')
            # 获取每个列表中的url
            child_ul = child_list.xpath('./ul/li/a/@href')
            # print(child_ul)
            for x in range(len(child_ul)):
                if not os.path.exists(filename + '/' + child_filename):
                    os.mkdir(filename + '/' + child_filename)
                t.submit(download, child_ul[x], filename, child_filename)

                # 普通模式下载,数度极慢
                # download(child_ul[x],filename,child_filename)

def download(url, filename, child_filename):
    html = etree.HTML(requests.get(url).text)
    # 获取小说章节的名称
    title_filename = html.xpath('/html/body/div[2]/div[3]/div[3]/div/div[1]/div[2]/div[2]/text()')[0]
    # 获取小说内容
    content = html.xpath('/html/body/div[2]/div[3]/div[3]/div/div[1]/div[5]/p/text()')
    # 在对应部分下创建对应名称的txt文档
    f = open(filename + '/' + child_filename + '/' + title_filename + '.txt', 'w', encoding='utf-8')
    for c in content:
        f.write(c + '\n')
    print(f'{
      
      child_filename}{
      
      title_filename}下载完毕!!!')

def main():
    t1 = time.time()
    # 调用下载的函数,采用base64解码加密后的网站
    get_down_url(str(base64.b64decode('aHR0cDovL2Jvb2suem9uZ2hlbmcuY29tL3Nob3djaGFwdGVyLzEwODU5OTkuaHRtbA=='))[1:].replace("'",""))
    print(f'下载完成!一共耗时:{
      
      time.time() - t1} 秒!!')

if __name__ == '__main__':
    main()


"""
xpath基础:
<div>
    <div>
        <span>aaa</span>
        <p>
            <span>bbb</span>
        </P>
    <div>
    <p>
        <span>ccc</span>
    </P>
</div>
# 表示div[1]下所有子类为span的值
num = x.xpath('./div[1]//span/text()')
输出,aaa,bbb,ccc
# 表示div[1]任意下一级后的下一级为span的值

num = x.xpath('./div[1]/*/span/text()')
输出 aaa,ccc
"""

线程池的下载数度还不是最快的,使用协程下载才能达到最快,而且下载数度还和电脑配置有关系,反正我的电脑需要用15s多钟,我试了一下使用云服务器的配置,只需要4s钟。

有兴趣的小伙拍可以尝试使用协程下载,我也在研究如何使用协程下载

补充一个关于bs4ku使用的小案例

# 安装
# Pip install bs4 -i 清华大学镜像下载链接
import csv
import os

from bs4 import BeautifulSoup
import requests


def base_bs4(url="http://www.shucai123.com/price/"):
    resp = requests.get(url)
    # print(resp.text)
    # 解析数据
    # 1.把页面源代码交给BeautifuSoup进行处理,生成bs对象
    page = BeautifulSoup(resp.text, "html.parser")  # 指定html解析器
    # 2.从bs对象中查找数据
    # find(标签,属性=值)
    # find_all(标签,属性=值)
    # table = page.find("table", class_="bjtbl")  # class是python的关键字
    table = page.find("table", attrs={
    
    "class": "bjtbl"})  # 和上面效果一样
    # print(table)
    # 拿出所有数据行
    trs = table.find_all("tr")[1:]
    for tr in trs:  # 每一行数据
        tds = tr.find_all("td")  # 拿到每行中的所有td
        time = tds[0].text  # .text 表示拿到被标签标记的内容
        origin = tds[1].text
        sort = tds[2].text
        pz = tds[3].text
        tel_name = tds[4].text
        # print(time,origin,sort,pz,tel_name)
        csvwriter.writerow([time, origin, sort, pz, tel_name])

    print("{}数据爬取完毕!".format(url))
    print('')


if __name__ == '__main__':
    if os.path.exists("菜价.csv"):
        os.remove("菜价.csv")
    f = open('菜价.csv', 'w', encoding='utf-8')
    csvwriter = csv.writer(f)
    for x in range(1, 5000):
        url = "http://www.shucai123.com/price/t" + str(x)
        base_bs4(url)
    f.close()

源代码以及更多爬虫实战案例gitee下载地址

猜你喜欢

转载自blog.csdn.net/weixin_45908488/article/details/125761062