Python多线程爬虫获取电影下载链接

一些电影资源网站往往广告太多,不想看广告所以做了这个程序

首先需要先分析网站的搜索链接,这里只用到了“爱下电影网”和“电影天堂”两个网站

爱下电影:http://www.aixia.cc/plus/search.php?searchtype=titlekeyword&q=%E9%80%9F%E5%BA%A6%E4%B8%8E%E6%BF%80%E6%83%85

电影天堂:http://s.dydytt.net/plus/so.php?kwtype=0&searchtype=title&keyword=%CB%D9%B6%C8%D3%EB%BC%A4%C7%E9

可以发现这两个网站搜索结果链接前部分可以固定死,后面肩上keyword(关键词)即可

所以我们的搜索链接可以按照这个规律直接拼接出来

爬虫基本思考:


Python多线程爬虫获取电影下载链接_第1张图片

二三级均为线程


首先对于queue模块,这是一种队列类型,也就是具有先入先出的特点,用这个来存放需要下载的链接

使用:

1.写入

object=queue.Queue()

object.put('what you want')

object.task_done()

2.读出

object.get()

注意如果没有对象在object中会出现堵塞

使用前一定先判断是否为空object.emoty()

其次就是thread模块

我是用的办法是创建自定义类继承与threading.Thread类


关于正则表达式这里就不再提了,我觉得正则表达式比BeautifulSoup和LXML好用一些



为了扩展性,每一个网站都用一个字典存放相关信息,这样以后需要添加其他网

站可以通过添加网站字典完成

设置一个url列表存放所有的网站信息字典

为了方便管理任务列表,我这里把所有任务放在一个key为网站名的字典中

变量展示:

task1=queue.Queue()
task2=queue.Queue()

Cannel={'爱下电影':task1,
        '电影天堂':task2
        }#队列的字典
downloadurl={'爱下电影':[],
             '电影天堂':[]}

"""
website中字典数据格式:
{
    'name':'网站名',
    'url':'网站地址半加工',
    'pat':[正则1,正则2],
    'root':'原本地址'
    'encode':'编码格式',
}
"""
aixiamovie={
    'name':'爱下电影',
    'url':r'http://www.aixia.cc/plus/search.php?searchtype=titlekeyword&q=',
    'root':r'http://www.aixia.cc',
    'pat':['

','οnclick="copyUrl(.*?)">'], 'encode':'utf-8' } tiantang={ 'name':'电影天堂', 'url':r'http://s.dydytt.net/plus/so.php?kwtype=0&searchtype=title&keyword=', 'root':r'http://s.dydytt.net', 'pat':["",''], 'encode':'gb2312', } weblist=[] weblist.append(aixiamovie) weblist.append(tiantang)




任务启动类:

class taskstart():
    def __init__(self,keyword):
        for item in weblist:#加工搜索地址
            temp=str(keyword.encode(item['encode']))
            temp=temp.replace(r'\x','%')
            temp=temp[2:]
            item['url']=item['url']+temp
        be=findurls(website=weblist)
        be.start()


在这个类中输入关键词,并根据网站的编码方式加工网站地址为搜索结果地址。并启动寻找详细链接的线程

这个对于多个关键词可以实例化多个该类型对象。


链接获取类:

class findurls(threading.Thread):
    def __init__(self,website):
        threading.Thread.__init__(self)#website是一个key为网站名,网址,正则表达式的字典集合成的列表
        self.website=website
        self.data=''
        self.id=''
        self.pat=''
        self.root=''
        self.encode=''
    def connect(self,url,counts=3):
        try:
            webpage=requests.get(headers=headers,url=url)
            webpage.encoding=self.encode
            self.data=webpage.text
        except Exception as f:
            print(f)
            if counts > 0:
                print('%s 连接失败,即将重新连接'%url)
                time.sleep(1)
                counts-=1
                self.connect(url=url,counts=counts)
            else:
                print("爬取失败")
    def urlgets(self):
        if self.data:
            res=re.findall(self.pat[0],self.data)
            canshu={
                'name':self.id,
                'pat':self.pat[1],
                'encode':self.encode
                }
            if res:
                 #这里可以开启爬虫线程了
                thread1=spdier(dic=canshu)
                thread1.start()
                for item in res:
                    item=self.root+item
                    Cannel[self.id].put(item)#根据网站名投入队列
                    Cannel[self.id].task_done()
            else:
                print("没有相关结果")
        else:
            print("没有返回数据,爬虫失败")
    def run(self):
        for item in self.website:
            self.id=item['name']
            self.pat=item['pat']#第一个正则获取详情连接 第二个正则获取下载连接
            self.encode=item['encode']
            self.connect(url=item['url'])
            self.root=item['root']
            self.urlgets()
        print("任务分配完成")
该类对象可以根据列表中的信息链接url获取信息,并通过正则表达式提取详情页面的链接并载入队列中,在载入队列前开启爬虫线程,开始对详情页面的提取

可以根据情况实例化多个该类型对象,分配url池


spdier类:

class spdier(threading.Thread):#通用爬虫
    def __init__(self,dic):#dic是一个字典key为pat,encode,name
        threading.Thread.__init__(self)
        self.id=dic['name']
        self.pat=dic['pat']
        self.encode=dic['encode']
        self.data=[]
        self.wait=5
        self.timeout=3
    def connect(self):
        try:
            if not Cannel[self.id].empty():#检测队列是否为空
                url=Cannel[self.id].get()
                print("%s has running for %s"%(self.id,url))
                webpage=requests.get(url=url,headers=headers,timeout=5)
                webpage.encoding=self.encode
                self.data.append(webpage.text)
                self.timeout=3
                self.wait=5
                self.connect()
               
            else:
                print("%s wait for task!"%(self.id))
                if self.wait>0:
                    self.wait-=1
                    time.sleep(1)
                    self.connect()
                else:
                    print("%s connect compelet!"%(self.id))
        except Exception as f:
            print(f)
            if self.timeout>0:
                self.timeout-=1
                time.sleep(1)
                self.connect()
            else:
                print("连接失败")
                self.connect()
    def getres(self):
        for each in self.data:
            res=re.findall(self.pat,each)
            #title=re.findall('(.*?)',each)#获取标题
            if res:
                for item in res:
                    downloadurl[self.id].append(item)
            else:
                print("没有相关连接")
    def run(self):
        self.connect()
        if self.data:
            self.getres()
            print("%s has make the result!"%self.id)
            save=open(r'f://'+self.id+'.txt','w')
            for d in downloadurl[self.id]:
                save.write(d)
                save.write('\n')
            save.close()
            print("%s work compelet!"%self.id)
        else:
            print("%s 缺少相关信息"%self.id)
这个类就直接根据相关信息获取下载链接并存在f盘中

贴上整体代码:

import requests
import re
import threading
import queue
import time

headers={
    'User-Agent':r'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0;  TheWorld 7)', 
    }
proxies={#代理配置

    }
task1=queue.Queue()
task2=queue.Queue()

Cannel={'爱下电影':task1,
        '电影天堂':task2
        }#队列的字典
downloadurl={'爱下电影':[],
             '电影天堂':[]}

"""
website中字典数据格式:
{
    'name':'网站名',
    'url':'网站地址半加工',
    'pat':[正则1,正则2],
    'root':'原本地址'
    'encode':'编码格式',
}
"""
aixiamovie={
    'name':'爱下电影',
    'url':r'http://www.aixia.cc/plus/search.php?searchtype=titlekeyword&q=',
    'root':r'http://www.aixia.cc',
    'pat':['

','οnclick="copyUrl(.*?)">'], 'encode':'utf-8' } tiantang={ 'name':'电影天堂', 'url':r'http://s.dydytt.net/plus/so.php?kwtype=0&searchtype=title&keyword=', 'root':r'http://s.dydytt.net', 'pat':["",''], 'encode':'gb2312', } weblist=[] weblist.append(aixiamovie) weblist.append(tiantang) class spdier(threading.Thread):#通用爬虫 def __init__(self,dic):#dic是一个字典key为pat,encode,name threading.Thread.__init__(self) self.id=dic['name'] self.pat=dic['pat'] self.encode=dic['encode'] self.data=[] self.wait=5 self.timeout=3 def connect(self): try: if not Cannel[self.id].empty():#检测队列是否为空 url=Cannel[self.id].get() print("%s has running for %s"%(self.id,url)) webpage=requests.get(url=url,headers=headers,timeout=5) webpage.encoding=self.encode self.data.append(webpage.text) self.timeout=3 self.wait=5 self.connect() else: print("%s wait for task!"%(self.id)) if self.wait>0: self.wait-=1 time.sleep(1) self.connect() else: print("%s connect compelet!"%(self.id)) except Exception as f: print(f) if self.timeout>0: self.timeout-=1 time.sleep(1) self.connect() else: print("连接失败") self.connect() def getres(self): for each in self.data: res=re.findall(self.pat,each) #title=re.findall('(.*?)',each)#获取标题 if res: for item in res: downloadurl[self.id].append(item) else: print("没有相关连接") def run(self): self.connect() if self.data: self.getres() print("%s has make the result!"%self.id) save=open(r'f://'+self.id+'.txt','w') for d in downloadurl[self.id]: save.write(d) save.write('\n') save.close() print("%s work compelet!"%self.id) else: print("%s 缺少相关信息"%self.id) class findurls(threading.Thread): def __init__(self,website): threading.Thread.__init__(self)#website是一个key为网站名,网址,正则表达式的字典集合成的列表 self.website=website self.data='' self.id='' self.pat='' self.root='' self.encode='' def connect(self,url,counts=3): try: webpage=requests.get(headers=headers,url=url) webpage.encoding=self.encode self.data=webpage.text except Exception as f: print(f) if counts > 0: print('%s 连接失败,即将重新连接'%url) time.sleep(1) counts-=1 self.connect(url=url,counts=counts) else: print("爬取失败") def urlgets(self): if self.data: res=re.findall(self.pat[0],self.data) canshu={ 'name':self.id, 'pat':self.pat[1], 'encode':self.encode } if res: #这里可以开启爬虫线程了 thread1=spdier(dic=canshu) thread1.start() for item in res: item=self.root+item Cannel[self.id].put(item)#根据网站名投入队列 Cannel[self.id].task_done() else: print("没有相关结果") else: print("没有返回数据,爬虫失败") def run(self): for item in self.website: self.id=item['name'] self.pat=item['pat']#第一个正则获取详情连接 第二个正则获取下载连接 self.encode=item['encode'] self.connect(url=item['url']) self.root=item['root'] self.urlgets() print("任务分配完成") class taskstart(): def __init__(self,keyword): for item in weblist:#加工搜索地址 temp=str(keyword.encode(item['encode'])) temp=temp.replace(r'\x','%') temp=temp[2:] item['url']=item['url']+temp be=findurls(website=weblist) be.start() keyword=input("请输入电影名称 ") main=taskstart(keyword=keyword)


Python多线程爬虫获取电影下载链接_第2张图片

Python多线程爬虫获取电影下载链接_第3张图片

最终获取的链接如图所示


这个程序缺点在于只适合于GET请求类型的网站,在后续中再加入了通用POST请求的方法。链接点击打开链接

你可能感兴趣的:(Python)