栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

python:线程池实践

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

python:线程池实践

# 通过官网单页拿到文章标题和发布时间,在通过抓包拿到浏览人数的数据
# 抓取所有页所有文章数据

from concurrent.futures import ThreadPoolExecutor
import requests
from lxml import etree
import csv

all_list = []  # 保存所有文章的信息
# 保存为csv格式
f = open("hunan.csv", mode="w", encoding="utf-8", newline="")
writer = csv.writer(f)


def main():
    baseurl = "http://www.hnuit.edu.cn/p1/mtsj.html"
    # 单独拿第一页吧,从第二页开始好一点
    get_data(baseurl)

    # 单纯死循环(链接会超时,可能是http链接占用过多只拿大页面也要请求20次)
    # for i in range(2, 20):
    #     url_resp_list = get_data(f"http://www.hnuit.edu.cn/p1/mtsj_{i}.html")
    #     print(url_resp_list)

    # 用多线程提高效率(可以解决http链接占用过多情况,缺点就是无顺序的)
    """用多线程view坑定不能按顺序拿到了,在一个循环里连续访问15个url拿到15个view,湖南信息学院不可能,如果用多线程去接这个任务,
    可以快速拿到15个view但是对不上号,你不知道那个view是那个的,可以试试开两个多线程"""
    # 要是单线程的话,一个线程要跑(19个主页面*每一个主页面要访问15次url拿到所有文章id)=285次
    with ThreadPoolExecutor(50) as t2:
        for i in range(2, 20):
            t2.submit(get_data, f"http://www.hnuit.edu.cn/p1/mtsj_{i}.html")
    # 看一下牛逼的湖南信息学院能拿多少信息
    print(f"此次拿到的数据为{len(all_list)}条")
    # 保存为csv格式
    save_data(all_list, len(all_list))


def save_data(save_list, num):
    print("sava...")
    # 注意是左闭右开
    for i in range(0, num):  # 每次拿多少我就存多少,这样就不会越界了,因为不可能每次都拿到135条,有一些页面可能404也不一定
        writer.writerow(save_list[i])
        print(f"第{i}条!")
    print("保存成功!")


def get_data(url):
    resp_page = ask_url(url)
    # 创建一个etree对象,并给定页面
    tree = etree.HTML(resp_page)
    # 用xpath()查找大致范围,拿到包含所有文章的标签信息
    li_list = tree.xpath("/html/body/div/div[2]/div[2]/ul[1]/li")
    # print(li_list) 查找到15个文章节点

    # 在每一篇文章里面拿详情链接后直接访问保存到列表
    """把这个循环改成多线程能不能解决超时问题?15个线程完成任务以后就返回一页中的所有文章信息"""
    with ThreadPoolExecutor(15) as t1:
        for li in li_list:
            t1.submit(base_date, li)
    return all_list


def base_date(li):
    """一页中的一个小文章的数据提取任务,是为了迎合多线程准备的"""
    list = []  # 保存一篇文章的信息
    time = li.xpath("./p[1]/text()")[0]
    title = li.xpath("./p[2]/a/text()")[0]
    id = li.xpath("./p[2]/a/@href")[0]
    # 把文章的id拿出来,不太会用分隔符截取,只能用切片
    id = id[18:23]
    # 通过访问链接拿观看人数
    view = get_view(id)
    list.append(title)
    list.append(view)
    list.append(time)
    all_list.append(list)


def get_view(id):
    """详情链接请求时没几个就超时了
        1.ip被封。(能请求就说明ip没被封)
        2.http的连接数超过最大限制。headers的Connection参数默认为keep-alive,导致之前所有的链接都一直存在,占用了后续的链接请求。
        3.网站服务器太差,爬取请求的速度太快。(它急着响应,而网站的服务器不给力,就直接断掉了)
        解决方案:
        1.换ip,更换headers或者使用代理ip。
        2.将Connection参数的值改为close。或者在requests.get前一行添加requests.adapters.DEFAULT_RETRIES = 5,意思是连接失败时重连五次。
        3.因为单线程请求过多url(单线程请求的url很一直占用)导致http的链接数量超过了最大限制(也可能是对方服务器不好)
        那么用多线程来解决就很好,多开几个线程,那么每个线程请求的url数量就会减少,很大程度上降低压力"""

    view_url = f"http://www.hnuit.edu.cn/content/view?contentId={id}"
    view_url_resp = requests.get(view_url)  # 因为那个方法返回的是text格式
    dic = view_url_resp.json()
    view = dic['data']['views']
    return view


# 拿到url的源代码
def ask_url(url):
    resp = requests.get(url)
    resp.encoding = "utf-8"
    # print(resp.text)  # 拿到了访问的页面
    return resp.text


if __name__ == "__main__":
    main()
    print("over!")
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1034828.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号