用python编写网页爬虫

        一、前期准备

        为了完成一个网页爬虫的小程序,需要有以下准备:

        1 了解基本的http协议

        2 urllib2库接口熟悉

        3 熟悉python正则表达式

        

        二、程序编写思路

        这里只是实现一个基本的网页爬虫程序,它的基本思路如下:

        1 寻找到需要抓取的网页,查看其源代码,分析需要获取网页页面的html规律

        2 利用urllib2库来读取所需要的网页

        3 利用正则表达式正确提取出所需要的网页信息

        4 对获取的网页数据信息进行有效性校验工作,即信息的甄别

        5 对有效的数据信息进行保存,如存放于文件,或数据库db中


        三、抓取网页代理服务器爬虫的实例

        找到一个代理服务器的网站,如http://www.cnproxy.com/,我们需要将http://www.cnproxy.com/proxy1.html下的IP,端口,type和area字段提取出来。主要利用正则表达式和urllib2库,代码如下:

        

proxylist1=Queue.Queue()#用于存放从页面中抓取的所有服务器代理IP地址和端口号
portdicts = {'z':"3", 'm':"4", 'a':"2", 'l':"9", 'f':"0", 'b':"5", 'i':"7", 'w':"6", 'x':"8", 'c':"1", 'r':"8", 'd':"0"}
def get_proxy_from_cnproxy():
    global proxylist1

    p = re.compile(r'''<tr><td>(.+?)<SCRIPT type=text/javascript>document.write\(":"\+(.+?)\)</SCRIPT></td><td>(.+?)</td><td>.+?</td><td>(.+?)</td></tr>''')
    
    
    for i in range(1,11):
        target = r"http://www.cnproxy.com/proxy%d.html" %i
        print target
        req = urllib2.urlopen(target)
        result =  req.read()
        matchs = p.findall(result)
        #print matchs
        
        for row in matchs:
            ip = row[0]
            port = row[1]
            if port is None:
                continue
            tmp = port.split('+')
            
            #发现在html中的端口找不到一些键所对应的值,过滤掉这些IP
            flag = 0
            for x in tmp:
                if x  not in portdicts:
                    flag = 1
                    break
            if flag == 1:
                continue
            
            port = map(lambda x: portdicts[x], port.split('+'))
            port = ''.join(port)
            agent = row[2]
            addr = row[3].decode("cp936").encode("utf-8")
        
            l = [ip, port, agent, addr]
            print l
            proxylist1.put(l)
        
    print "page 1-10 size:%s nums proxy info" %proxylist1.qsize()  
        

        上述代码完成将所需要的网页字段提取出来存放到队列proxylist1中。紧接着需要对队列proxylist1中的每个字段进行校验,判断里面数据的有效性,然后将检测到的数据存放于另一队列ProxyCheckedList中,然后对有效的数据信息进行一个排序,最后将其保存于文件中。代码如下:

ProxyCheckedList = Queue.Queue()#用于存放经校验后得到的有效代理IP地址和端口号信息        
class ProxyCheck(threading.Thread):
    def __init__(self, fname):
        threading.Thread.__init__(self)
        self.timeout = 5
        #self.test_url = "http://www.baidu.com/"
        #self.test_str = "030173"
        #self.test_url = "http://www.so.com/"
        #self.test_str = '08010314'
        self.test_url="http://www.renren.com"
        self.test_str="110000000009"
        self.fname = fname
        self.checkedProxyList = []
        
    def checkProxy(self):
        threadpool = []
        for i in range(10):#开辟10个线程放到线程池中
            threadpool.append(ck_process(self.test_url, self.test_str,self.timeout,i))
        
        #启动10个线程同时处理校验工作    
        map(lambda x: x.start(), threadpool)
        
        #等待线程退出
        map(lambda x: x.join(), threadpool)
        
        while ProxyCheckedList.empty() == False:
            try:
                content = ProxyCheckedList.get_nowait()
            except Exception,e:
                print e
            else:
                self.checkedProxyList.append(content)
        print "the checked proxylist contains: %s nums records"%len(self.checkedProxyList)
        for info in self.checkedProxyList:
            print info
        
    def sort(self):
        sorted(self.checkedProxyList, cmp=lambda x,y:cmp(x[4], y[4]))#对响应时间的代理ip列表进行排序
    
    def save(self):
        f = open(self.fname, 'w+')
        for proxy in self.checkedProxyList:
            f.write("%s:%s\t%s\t%s\t%s\n"%(proxy[0], proxy[1], proxy[2], proxy[3], proxy[4]))
        f.close()
    
    def run(self):
        self.checkProxy()
        self.sort()
        self.save()
        print 'Done'
        这个类主要继承于线程类threading,它的程序流程主要看run(),它的过程就是上面分析的思路。下面对checkProxy()这个过程进行简要说明,它创建了10个线程,利用map函数让这十个线程同时启动,最后是等待线程的退出。然后对队列中ProxyCheckedList的数据再次加工就完成了。而这10个线程他们干的事情是相同的,他们依次从一个队列ProxyCheckedList中读出10条http代理数据(IP,端口等),然后迭代对这10条数据进行有效性判断,有效性判断的思路如下:

        用urllib2.HTTPCookieProcessor()创建一个cookie,

        利用每个数据的IP和端口构定一个代理句柄对象proxy_handler = urllib2.ProxyHandler({"http":r'http://%s:%s'%(proxy[0],proxy[1])})

        将代理句柄与cookie绑定opener = urllib2.build_opener(cookies, proxy_handler)

        请求对象的安装urllib2.install_opener(opener)

        最后是利用这个代理IP访问某个网站,如果在某一规定的时间内有数据返回,则说明有效,将其放至队列ProxyCheckedList中,否则迭代下一个。下面是代码:

class ck_process(threading.Thread):
    '''线程类:用于多线程处理校验代理IP的有效性'''
    
    def __init__(self,test_url, test_str, timeout,count):
        threading.Thread.__init__(self)
        self.proxy_contain = []
        self.test_url = test_url
        self.test_str = test_str
        self.checkedProxyList = []
        self.timeout = timeout
        self.count = count
    def run(self):
        
        cookies = urllib2.HTTPCookieProcessor()#构造一个cookie对象
        #print "I'm thread process No. %s" %self.count
        while proxylist1.empty() == False:
            if lock_que.acquire():#成功获取锁
                if proxylist1.qsize() >= 10:
                    number = 10
                else:
                    number = proxylist1.qsize()
                    
                for i in range(number): #从原始的列表队列中获取出10条代理IP信息
                    proxy = proxylist1.get_nowait()
                    self.proxy_contain.append(proxy)
                    #print "%s thread process:%s"%(self.count,self.proxy_contain)
                    #print
                lock_que.release()
            
                
            #每个线程每次逐一处理10条    
            for proxy in self.proxy_contain:    
            
                proxy_handler = urllib2.ProxyHandler({"http":r'http://%s:%s'%(proxy[0],proxy[1])})#构造一个代理句柄对象
                opener = urllib2.build_opener(cookies, proxy_handler)#将代理句柄与cookie绑定
            
                #模拟一个浏览器,加入http的user-agent头字段,参数放入列表的元组
                opener.addheaders=[('user-agent','Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31')]
                urllib2.install_opener(opener)#请求注册
                t1 = time.time() #get current time
                try:#有时某些代理无效打不开网站
                    req = urllib2.urlopen(self.test_url, timeout = self.timeout)
                    result = req.read()
                    timeused = time.time() - t1
                    pos = result.find(self.test_str)
        
                    if pos > 1:
                        self.checkedProxyList.append((proxy[0],proxy[1], proxy[2], proxy[3], timeused))
                    else:
                        continue
                    
                except Exception, e:
                    #print e.message
                    continue
        
        if len(self.checkedProxyList) != 0:
            if lock_que_cked.acquire():
                for proxy in self.checkedProxyList:
                    ProxyCheckedList.put(proxy)
                lock_que_cked.release()
         
        print "%s thread process:out: %s nums"%(self.count, len(self.checkedProxyList))
        (完)
  


   

        

     

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值