抓取大学排名

示例图片


1.0版本

import requests
from lxml import etree


max_requests = 5
requests_count = 0

# 抓取单个大学链接,如http://qianmu.iguye.com/哈佛大学
r = requests.get("http://qianmu.iguye.com/2018USNEWS世界大学排名")
dom = etree.HTML(r.text)
links = dom.xpath("//*[@id='content']/table/tbody/tr/td[2]/a/@href")
for link in links:
    requests_count += 1
    if requests_count > max_requests:
        break
    if not link.startswith("http://"):
        link = 'http://www.qianmu.org/%s'%link
    print(link)

    # 抓取表格内容
    r = requests.get(link)
    dom = etree.HTML(r.text.replace("\t",""))
    # 抓取第一列的内容
    keys = dom.xpath("//div[@id='wikiContent']/div[@class='infobox']/table/tbody/tr/td[1]//text()")
    # print(keys)
    # 抓取第二列的内容
    cols = dom.xpath("//div[@id='wikiContent']/div[@class='infobox']/table/tbody/tr/td[2]")
    values = [",".join(col.xpath('.//text()')) for col in cols]
    # print(values)
    # info = {}
    # for i in range(len(keys)):
    #     info[keys[i]] = values[i]
    info = dict(zip(keys, values))
    print(info)

2.0版本,封装函数

import requests
from lxml import etree


# 入口页面地址
start_url = "http://qianmu.iguye.com/2018USNEWS世界大学排名"
# 存放待抓取页面地址
link_queue = []


def fetch(url):
    """执行网页的抓取"""
    r = requests.get(url)
    # 返回抓取的页面内容并取出页面中的制表符
    return r.text.replace("\t","")


def parse(html):
    """解析入口页面"""
    dom = etree.HTML(html)
    # 获取页面中的表格每一行的第二列中的超链接
    links = dom.xpath("//div[@id='content']/table/tbody/tr/td[2]/a/@href")
    # 将这些链接放入待抓取队列中
    link_queue.extend(links)


def parse_university(html):
    """解析大学详情页面"""
    dom = etree.HTML(html)
    # 选择出表格的父节点,以减少重复代码
    infobox = dom.xpath("//div[@id='wikiContent']/div[@class='infobox']")[0]
    # 选择出表格中每一行的第一列中的文本
    keys = infobox.xpath("./table/tbody/tr/td[1]//text()")
    # 选择出表格中每一行的第二列节点
    cols = infobox.xpath(".//table/tbody/tr/td[2]")
    # 便利第二列的节点,病提取出每一个单元格中的文本
    values = [",".join(col.xpath(".//text()")) for col in cols]
    # info = {}
    # for i in range(len(keys)):
    #     info[keys[i]] = values[i]
    # print(info)
    # 讲第一列、第二列中的数据合并成一个字典,组成大学信息
    info = dict(zip(keys, values))
    print(info)


if __name__ == "__main__":
    # 抓取并处理入口页面,提取首页内的大学页面链接
    parse(fetch(start_url))

    # 最大请求数
    max_requests = 5
    # 请求计数器
    requests_count = 0

    # 反转队列,以便先进先出
    link_queue.reverse()
    while link_queue:
        # 获取最前面的一个链接
        link = link_queue.pop()
        requests_count += 1
        if requests_count > max_requests:
            break
        # 如果有不规则的链接,则补全
        if not link.startswith("http://"):
            link = "http://qianmu.iguye.com/%s" % link
        # 抓取并处理大学详情页面
        print(link)
        parse_university(fetch(link))


# print("%s links"% len(links))

3.0版本,多线程

import threading
from queue import Queue
import requests
import time
from lxml import etree


# 入口页面地址
start_url = "http://qianmu.iguye.com/2018USNEWS世界大学排名"
# 存放待抓取页面地址
link_queue = Queue()
# 下载器线程数量
DOWNLOADER_NUM = 10
# 线程池
threads = []
# 统计下载链接的数量
download_pages = 0


def fetch(url):
    """执行网页的抓取"""
    r = requests.get(url)
    global  download_pages
    download_pages += 1
    # 返回抓取的页面内容并取出页面中的制表符
    return r.text.replace("\t","")


def parse(html):
    """解析入口页面"""
    dom = etree.HTML(html)
    # 获取页面中的表格每一行的第二列中的超链接
    links = dom.xpath("//div[@id='content']/table/tbody/tr/td[2]/a/@href")
    # 将这些链接放入待抓取队列中
    for link in links:
        # 如果有不规则的链接,则补全
        if not link.startswith("http://"):
            link = "http://qianmu.iguye.com/%s" % link
        # 将链接放入下载队列
        link_queue.put(link)


def parse_university(html):
    """解析大学详情页面"""
    dom = etree.HTML(html)
    # 选择出表格的父节点,以减少重复代码
    infobox = dom.xpath("//div[@id='wikiContent']/div[@class='infobox']")[0]
    # 选择出表格中每一行的第一列中的文本
    keys = infobox.xpath("./table/tbody/tr/td[1]//text()")
    # 选择出表格中每一行的第二列节点
    cols = infobox.xpath(".//table/tbody/tr/td[2]")
    # 便利第二列的节点,病提取出每一个单元格中的文本
    values = [",".join(col.xpath(".//text()")) for col in cols]
    # 讲第一列、第二列中的数据合并成一个字典,组成大学信息
    info = dict(zip(keys, values))
    print(info)


def downloader():
    """下载器,主要执行下载和解析操作"""
    while True:
        # 从队列中读取一个链接,如果没有,则阻塞
        link = link_queue.get()
        # 如果收到的链接是None,则退出循环
        if link is None:
            break
        # 下载并解析大学详情网页
        print(link)
        parse_university(fetch(link))
        # 向队列发送任务完成信号
        link_queue.task_done()
        print("remining queue: %s"%link_queue.qsize())


if __name__ == "__main__":
    # 抓取并处理入口页面,提取首页内的大学页面链接
    start_time = time.time()
    parse(fetch(start_url))

    for i in range(DOWNLOADER_NUM):
        t = threading.Thread(target=downloader)
        t.start()
        threads.append(t)
    # 让队列一直阻塞到全部任务完成
    link_queue.join()

    # 向队列中发送DOWNLOADER_NUM个None
    for i in range(DOWNLOADER_NUM):
        link_queue.put(None)

    # 退出线程
    for t in threads:
        t.join()

    print("download %s page in %.2f seconds"%(download_pages,time.time()-start_time))

4.0版本,分布式爬虫(多线程+多进程)

import signal
import threading
from queue import Queue
import redis
import requests
import time
from lxml import etree


# 入口页面地址
start_url = "http://qianmu.iguye.com/2018USNEWS世界大学排名"
# 存放待抓取页面地址
# link_queue = Queue()
# 下载器线程数量
DOWNLOADER_NUM = 10
# 下载延迟
DOWNLOADER_DELAY = 0.1
# 线程池
threads = []
# 统计下载链接的数量
download_pages = 0


r = redis.Redis()
thread_on = True


def fetch(url):
    """执行网页的抓取"""
    r = requests.get(url)
    global  download_pages
    download_pages += 1
    # 返回抓取的页面内容并取出页面中的制表符
    return r.text.replace("\t","")


def parse(html):
    """解析入口页面"""
    dom = etree.HTML(html)
    # 获取页面中的表格每一行的第二列中的超链接
    links = dom.xpath("//div[@id='content']/table/tbody/tr/td[2]/a/@href")
    # 将这些链接放入待抓取队列中
    for link in links:
        # 如果有不规则的链接,则补全
        if not link.startswith("http://"):
            link = "http://qianmu.iguye.com/%s" % link
        # 将链接放入下载队列
        # link_queue.put(link)

        if r.sadd("qianmu.seen",link):
            r.rpush("qianmu.queue",link)


def parse_university(html):
    """解析大学详情页面"""
    dom = etree.HTML(html)
    # 选择出表格的父节点,以减少重复代码
    infobox = dom.xpath("//div[@id='wikiContent']/div[@class='infobox']")[0]
    # 选择出表格中每一行的第一列中的文本
    keys = infobox.xpath("./table/tbody/tr/td[1]//text()")
    # 选择出表格中每一行的第二列节点
    cols = infobox.xpath(".//table/tbody/tr/td[2]")
    # 便利第二列的节点,病提取出每一个单元格中的文本
    values = [",".join(col.xpath(".//text()")) for col in cols]
    # 讲第一列、第二列中的数据合并成一个字典,组成大学信息
    info = dict(zip(keys, values))
    # print(info)
    r.lpush("qianmu.item",info)


def downloader(i):
    """下载器,主要执行下载和解析操作"""
    while thread_on:
        # 从队列中读取一个链接,如果没有,则阻塞
        link = r.lpop("qianmu.queue")
        # 如果收到的链接是None,则退出循环
        if link:
            # 下载并解析大学详情网页
            parse_university(fetch(link))
            print("remining-%s queue: %s"%(i,r.llen("qianmu.queue")))
        time.sleep(DOWNLOADER_DELAY)
    print("Thread-%s exit now..." % i)


def signal_handler(signnum,frame):
    print("received CRTL+C, wait for exit gracfully...")
    global thread_on
    thread_on = False


if __name__ == "__main__":
    # 抓取并处理入口页面,提取首页内的大学页面链接
    start_time = time.time()
    parse(fetch(start_url))

    for i in range(DOWNLOADER_NUM):
        t = threading.Thread(target=downloader,args=(i+1,))
        t.start()
        threads.append(t)
        print("Thread(%s) started..." %t.name)

    signal.signal(signal.SIGINT,signal_handler)

    # 退出线程
    for t in threads:
        t.join()

    # 计算程序执行消耗的时间
    print("download %s page in %.2f seconds"%(download_pages,time.time()-start_time))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值