您的位置:首页 > 其它

抓取大学排名

2018-02-05 17:16 393 查看
示例图片





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))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: