用python爬取某美剧网站的下载链接(一)

news/2024/7/19 12:25:48 标签: python, 爬虫

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

       心血来潮, 想要了解一下爬虫的基本原理, 本着目的驱动的原则, 想要把某美剧下载网站上的聚集下载链接都爬下来,个人收藏;  第一次写, 不是什么教程,只是记录一下自己的思路和一些留着以后深入的点, 写的太乱,还请轻喷..

         既然是目的驱动,因此每个涉及到的点在本文中都点到为止,接下来我自己也会逐步更深入的了解, 文章只是一个备忘录, 以免稍后遗忘;

         一个最简单的爬虫,通常有着相似的设计思路从一个页面开始, 分析得到所有感兴趣的内容(保存)和链接, 再依次访问这些链接进行同样的操作, 直到不能继续为止:

        1. 记住已经访问过的链接,再次遇到时不会访问,避免陷入循环(x)

        2. 以合适的结构和方式存储获取到的数据(x)

        因为本文的目的和对应的网站的链接及富有规律性, 且要爬取得内容也很明确(而不是像搜索引擎一样几乎要保存所有内容),因此以上两点均不涉及, 最后只是简单的使用XML保存拿到的数据;

分析对应的站点:

       版权问题, 这里掩码了目标网站;

       本文要爬取的网站,首先有一个分页的目录, 每页展示一部分美剧的简介和详情页面的链接, 这个页面的地址是http://www.xxxxx.net/ddc1/page/x  末尾的x是从1开始的自然数;

       详情页面的地址是 http://xxxxx.net/archives/xxxxx/ 末尾的xxxxx是随机的1-5位数,无规律,并非每个数字都有页面, 因此详情页面的链接,需要从目录页面提取,以免做很多无用的工作;

       目录页面, 每一部剧都在一个classthumbnaildiv中:

<div class="thumbnail">
   <a href="http://xxxxx.net/archives/23352/" rel="bookmark" title="生存指南第一季/全集Cooper Barrett.迅雷下载">
     <img class="home-thumb" src="http://xxxxx.com/soohf5.jpg" width="140px" height="100px" alt="生存指南第一季/全集Cooper Barrett.迅雷下载"/>
   </a>
 </div>

    因此可以很方便的使用下面的正则表达式取出我们需要的内容:

python"><div>.*?<a href="(.*?)" rel="bookmark" title="(.*?)">

   同理,分析详情页面, 我们得到了下面的正则表达式,取出所有的下载链接:

python"><a href="((magnet|ed2k):.*?)">(.*?)</a>

    .*? 这个问号,表示着我们需要最小匹配, 因为页面中有着很多循环的内容;

. http请求

     使用urllib2来进行http请求;

     首先使用urllib2.Request来封装一次请求, 其中第二个参数,设置了一个header,其中模拟了User-AgentIE, 简单的以免部分网站拦截我们的爬虫;

     最后,对获取到的page,utf-8解码, 成为unicode (python内部的字符串都是unicode)

python">self.header = {
     'User-Agent': 'Mozilla/4.0 (compatible; MSIE 9.0; Windows NT)'
}
url = self.DIC_LINK + str(page_no)
req = Request(url, headers=self.header)
response = urlopen(req)
cur_page = response.read()
unicode_page = cur_page.decode("utf-8")

urlopen方法可能会抛出异常(HTTPError, URLError), HTTPError继承自URLError, 因此应优先捕获HTTPError; HTTPErrorcode, 是一个整形数, 也就是我们常见的404, 500http返回码, 经过测试,目录列表的地址,当页数超过了已有的最大页数的时候,网站会返回404, 所以可以把这个当作一个结束的标识;

. 正则表达式

     python的正则表达式用起来很顺手, 引入 re 模块就可以愉快的使用了;

    首先使用compile方法获得模式对象, 注意第二个参数 re.S ,使得 . 可以匹配换行符

    然后调用findall方法,就能获得所有的匹配了;

    正则表达式中, 括号() 围起来的,会成为一个分组, 从左到又, 每遇到一个(, 则分组加1, 因此我们得到的items数组中, 每一个元素,又是一个数组, 这个数组的第一个元素为链接, 第二个元素为title的值;

python">    reg_str = r'<div>.*?<a href="(.*?)" rel="bookmark" title="(.*?)">'     
    reg = re.compile(reg_str, re.S)     
    items = re.findall(reg, unicode_page)

. 结构

     下面,可以开始组装逻辑了;

      简单的先将需要访问的链接存在一个队列中, 每次从队列中取出链接访问,获取内容;

      这样就将爬取目录页面和详情页面的逻辑分开了;

    下面是目录页面的方法:

python">def get_show_thread(self):
    end = False
    for page_no in range(1, 9999):
        if end:
            break
        url = self.DIC_LINK + str(page_no)
        req = Request(url, headers=self.header)
        flag = True
        while flag:
            try:
                response = urlopen(req)
                cur_page = response.read()
                unicode_page = cur_page.decode("utf-8")
                self.get_show(unicode_page)
                flag = False
            except HTTPError, e:
                print e
                if e.getcode() == 404:
                    self.total = self.total_count
                    end = True
                    break
            except URLError:
                sleep(1)
                
def get_show(self, unicode_page):
    reg_str = r'<div class="thumbnail">.*?<a href="(.*?)" rel="bookmark" title="(.*?)">'
    reg = re.compile(reg_str, re.S)
    items = re.findall(reg, unicode_page)
    self.total_count += len(items)
    for item in items:
        self.show_link.append(item)

     使用一个数组show_link,保存要访问的详情页面的链接;

    接下来,主线程中, 不断访问show_link, 如果其中有链接, 便取出来访问, 爬取详情页面的下载链接, 之后把这个链接从数组中删除;

python">def get_download_link(self):
    while True:
        if len(self.show_link) > 0:
            url = self.show_link[0][0]
            notice = u'抓取' + url.encode('utf-8')
            notice += (r' ' + str(self.count) + r'/' + str(self.total_count))

            print notice
            req = Request(url, headers=self.header)
            response = urlopen(req)
            cur_page = response.read()
            unicode_page = cur_page.decode("utf-8")

            reg_str = r'<a href="((magnet|ed2k):.*?)">(.*?)</a>'
            reg = re.compile(reg_str, re.S)
            items = re.findall(reg, unicode_page)

            self.save_links(items, self.show_link[0][1])
            del self.show_link[0]
        else:
            sleep(0.5)

   --TODO-- 最后,我们按照格式,将得到的数据保存为xml文件  --TODO--

  下一篇记录下xml事;

上文中的代码,是截取自完整的代码, 里面有很多变量和一些print, 主要是便于在查看运行进度(1000多个网页,在一台机器顺序执行,且没有做性能优化,因此是很费时间的....);


转载于:https://my.oschina.net/u/587108/blog/598444


http://www.niftyadmin.cn/n/1501341.html

相关文章

CentOS下nginx简单安装

说明&#xff1a;环境 系统&#xff1a;Centos 6 软件包&#xff1a;nginx-1.2.4配置系统yum源 #/etc/yum.repos.d/ #rm -rf ./* vi localhost.repos.d [yumyuan] nameCentOS-$releasever - Media #自定义名称 baseurlfile:///mnt/cd…

Java API —— 多线程(2)

1、JDK5中Lock锁的使用   虽然我们可以理解同步代码块和同步方法的锁对象问题&#xff0c;但是我们并没有直接看到在哪里加上了锁&#xff0c;在哪里释放了锁&#xff0c;为了更清晰的表达如何加锁和释放锁&#xff0c;JDK5以后提供了一个新的锁对象Lock。   Lock     …

简单的cookie读写封装

<!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><title>简单的cookie封装</title></head><body></body><script>var cookies{name:this.name,value:this.value,day:this.day,set…

都说软件测试工作不难有手就行,但为何这么多劝退的?

上一个说软件测试简单的&#xff0c;已经被面试官问emo了... 现在已经过了 ”不会但我会学“ 就能感动面试官的时代&#xff0c;随着供需关系的变化&#xff0c;不论是对于面试官还是面试者&#xff0c;面试的成本越来越高。为了筛选到更优秀的程序员&#xff0c;面试官们可谓…

一句sql执行过程

一.大概过程 客户端通过网络协议把语句发送到服务端&#xff0c;服务端接收到请求后会分配一个线程&#xff0c;因为MySQL是单线程的&#xff0c;所以任意时刻都只有一个线程在执行&#xff0c;而其他的线程会处于等待状态&#xff0c;-》然后会再缓存里查看是否有已经查询到的…

深圳出差有感

来深圳已经三天了&#xff0c;见了一些朋友&#xff0c;提及一些过去的事情&#xff0c;感慨万千&#xff0c;转眼间好多年过去&#xff0c;每一个人都产生了很多变化&#xff0c;个人&#xff0c;家庭&#xff0c;生活&#xff0c;工作......&#xff0c;人生的追求也变得不同…

辗转相除法的证明

描述&#xff1a;关于辗转相除法的具体实现在这里就不具体说明了&#xff0c;本文要记录的是辗转相除法应用于求最大公约数的算法证明过程。 假设&#xff1a; 求m和n的最大公约数。a,b分别是m除以n的商和余数&#xff0c;即mnab。gcd(m,n)表示m和n的最大公约数。  求证&…

如何学习软件测试开发?从入门到精通?

如何学习软件测试开发&#xff1f;从入门到精通&#xff1f;刚开始学习软件测试的同学要经历一段从学习到入行再到熟练的过程。掌握软件测试基础知识、学习软件测试的思维、将理论知识运用到实践中&#xff0c;做到真正的理解软件测试的理论知识。作为软件测试工程师应该搞清楚…