串行处理几百个网页还勉强,在爬取拥有100万网页的大型网站时,耗时超过11天(假设每秒1个网页的速度)
4.1
目标:
从http://s3.amazonaws.com/alexa-static/top-1m.csv.zip中获取全球热门网站列表
并取前500个网站用链接爬虫爬取
from io import BytesIO,TextIOWrapper
import requests
from zipfile import ZipFile
url='http://s3.amazonaws.com/alexa-static/top-1m.csv.zip'
urls=[]
resp=requests.get(url,stream=True)
with ZipFile(BytesIO(resp.content)) as zf:
csv_name=zf.namelist()[0]
with zf.open(csv_name) as csv_file:
for item in csv_file:
website=item.decode('utf-8').split(',')[1]
urls.append(website)
抽象成Alexa类:
import csv
from zipfile import ZipFile
from io import TextIOWrapper, BytesIO
import requests
class AlexaCallback:
def __init__(self, max_urls=500):
self.max_urls = max_urls
self.seed_url = 'http://s3.amazonaws.com/alexa-static/top-1m.csv.zip'
self.urls = []
def __call__(self):
resp = requests.get(self.seed_url, stream=True)
with ZipFile(BytesIO(resp.content)) as zf:
csv_filename = zf.namelist()[0]
with zf.open(csv_filename) as csv_file:
for _, website in csv.reader(TextIOWrapper(csv_file)):
self.urls.append('http://' + website)
if len(self.urls) == self.max_urls:
break
爬取目标改变
由于墙太厚,爬取速度太慢
我将爬取目标改为了爬取http://top.chinaz.com/上前500个购物网站
只获取内链的代码
if not re.match('^(/|'+domain+')',href):#筛选出内部网页
continue
4.2串行爬虫
相比之前的链接爬虫添加了:
1.爬取的域名变了,需要更新对每个站点中的robots.txt文件的处理方式。
2. url路径合法性问题
串行爬虫所用时间
以下代码从http://top.chinaz.com/获取排名前500的购物网站并且写入到本地
import requests
from bs4 import BeautifulSoup
import re
import json
import sys
import csv
sys.path.append('..')
from download import download
'''
从Chinaz.com爬取最受欢迎的前几百个网页存入列表
'''
class GetWebList(object):
def __init__(self,web_num=100,max_page=20):#web_num:需要的网页数 max_page:要爬取多少页
self.web_num=web_num
self.web_li=[]
self.max_page=max_page
def __call__(self):
start_url='http://search.top.chinaz.com/top.aspx?p='
page=1
while page
核心代码部分:
while crawl_li:
#观察urls发现 待爬取列表中都缺少http协议
url=crawl_li.pop()
print('url:',url)
domain='http://'+urlparse(url).netloc
no_robots=False
rp=robots.get('domain')
if not rp:#不在robots缓存
robot_url='{}/robots.txt'.format(domain)
rp=get_robot_parser(robot_url)
if not rp:
no_robots=True
else:
robots[domain]=rp
if no_robots or rp.can_fetch(user_agent,url):
depth=seen.get(url,0)
if depth==max_depth:#判断深度
print('this may be a trap:',url)
continue
html=d(url)
if not html:
continue
href_li=re.findall("""
爬取用时:
#由于只是为了学习爬取,没有对每个待爬网站做定制化处理
#有部分网站爬取失败
386.28738594055176
4.3多线程爬虫
多线程爬虫,提高cpu利用率
不需要上锁,不会导致死锁情形
顺便复习下python多线程相关知识
常规思路是在主线程中:
定义一个线程方法,里面是线程要执行的操作
定义一个线程队列,实时记录线程的情况
因此,要将单线程链接爬虫该为多线程,只要将涉及待爬取队列的操作由多个线程操作即可
相关代码:
def process_queen():#线程的操作函数
while crawl_li:
#观察urls发现 待爬取列表中都缺少http协议
url=crawl_li.pop()
print('url:',url)
domain='http://'+urlparse(url).netloc
no_robots=False
rp=robots.get('domain')
if not rp:#不在robots缓存
robot_url='{}/robots.txt'.format(domain)
rp=get_robot_parser(robot_url)
if not rp:
no_robots=True
else:
robots[domain]=rp
if no_robots or rp.can_fetch(user_agent,url):
depth=seen.get(url,0)
if depth==max_depth:#判断深度
print('this may be a trap:',url)
continue
html=d(url)
if not html:
continue
href_li=re.findall("""
多进程爬虫
暂时不作了解