用lxml跑一个简单的流程 3.0版本

多进程抓取页面
  1. 导入第三方thread包,定义一个进程池
  2. 将抓取的一级页面放进进程池里
  3. 启动进程池,自定义用几个进程来执行函数
  4. 在进程池中引入函数,定义download函数,执行二级抓取数据
  5. 退出线程
# import 先导入内置的库,再导入第三方库
import time
import threading
from queue import Queue
import lxml.etree
import requests

START_URL= 'http://qianmu.iguye.com/2018USNEWS世界大学排名'
# 启动的线程数量
DOWNLOAD_LINE = 10
# 定义Queue,队列,保存等抓取的url
link_queue = Queue()
# 线程列表,保存Thread对象
threads = []
download_pages = 0


def fetch(url, raise_err=True):
    global download_pages
    try:
        # 使用requests抓取url
        r = requests.get(url)
        r.encoding = 'utf-8'
        # 每读取一个,加1,显示已经读取的数据
        download_pages += 1
        return r.text
    except Exception as e:
        # 如果报错则print出来
        print(e)
    else:
        # 如果没报错,则检查http的返回码是否正常
        if raise_err:
            r.raise_for_status()


def parse_university(html):
    selector = lxml.etree.HTML(html)
    title = selector.xpath('//*[@id="wikiContent"]/h1/text()')[0]
    # 打印大学名
    print(title)

    infobox = selector.xpath('//div[@class="infobox"]')[0]
    keys = infobox.xpath('./table//tr/td[1]/p//text()')
    cols = infobox.xpath('./table//tr/td[2]')
    values = [''.join(col.xpath('.//text()')) for col in cols]

    # 用列表的形式循环出keys, values
    for k, v in zip(keys, values):
        print('%s:%s'%(k, v))
    print('-' * 30)


# 线程执行这个函数,不退出,一直到link为空
def download():
    while True:
        # get阻塞方法
        link = link_queue.get()
        if link is None:
            break
        # 执行下载、解析操作
        parse_university(fetch(link))
        # 向队列发送完成任务的消息
        link_queue.task_done()
        print('remaining queue: %s' % link_queue.qsize())


if __name__ == '__main__':
    start_time = time.time()
    selector = lxml.etree.HTML(fetch(START_URL))
    links = selector.xpath('//*[@id="content"]/table/tbody/tr/td/a/@href')

    # 第一步,抓取第一个页面放进Q里面
    for link in links:
        # 加判断,如果链接有错,重新给附个链接
        if not link.startswith('http://'):
            link = 'http://qianmu.iguye.com/%s' % link
        link_queue.put(link)

    # 第二步,启动线程
    for i in range(DOWNLOAD_LINE):
        t = threading.Thread(target=download)
        t.start()
        # 把读入的内容
        threads.append(t)
    # 堵塞,前面的都执行完了之后,再执行他,然后退出程序
    link_queue.join()

    # 向队列发送DOWNLOADER_NUM个None,以通知线程退出
    for i in range(DOWNLOAD_LINE):
        link_queue.put(None)

    # 退出线程
    for t in threads:
        t.join()
    # 计算抓取的耗时
    cost_seconds = time.time() - start_time
    print('download %s pages in %.2f seconds'%(download_pages, cost_seconds))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值