如何用Python爬取电影天堂磁力链接【01】?

今天我们讲的是Python的实战练习:爬取电影天堂的磁力链接。

关注公众号【老夫撸代码】回复【python01】获取python交流QQ群相关信息。

关注老夫的宝子们都知道,老夫业余时间撸了一个电影网站,主要是用Laravel搭建的,里面的数据就是用Python爬取的某个电影天堂网站资源。

在我们明确了业务需求后,主要分为以下三个步骤。

1、目标网站分析

首先,我们需要寻找适合爬虫的网站。

目前一般网站的技术架构分为以下几类:

  1. 前后端分离的网站

    这类型网站主要是用 vue 或者 react 进行前端构建,后端使用java 或者 php 提供接口,为了便于SEO优化,可能会采用ssr进行服务端渲染。本质还是返回给前端一个完整的html页面。

  2. cms网站

    此类型网站本质还是返回给前端一个html页面,不同的是需要模板语言做支持,比如wordpress、织梦、帝国等等建站工具

  3. js动态加载的网站

    这类型的网站的一个特点是返回给前端也是一个html页面,而数据是放到 js 的全局变量里面,然后再通过操作dom把数据渲染出来。

总之,技术千变万化,我们需要透过现象看到本质,俗话说:你有张良计,我有过墙梯。

我们在百度随便搜索“电影天堂”这几个关键字的时候会显示一堆资源站,随便选一个网站,参照上面的技术架构分类进行判断。

这里老夫选择了这个网站:

F12看下源码结构,发现是直接输出网页的形式,也就是第2种方式,这是最适合爬虫爬取的数据结构。

2、技术架构

通过分析整个网站的网页结构,我们可以先从导航栏入手。

一般网站设计的基本结构是列表页 + 详情页。这里列表页就是每个电影的分类,详情页就是列表页种具体的某个电影的页面。

(列表页)

(详情页)

因此我们可以初步确定爬取的思路:

1、先爬取所有的列表页的列表数据

2、然后再进入详情页爬取资源链接

这里我们可以这样设计,把所有电影资源分类下的列表页的url保存到本地,然后通过加载本地的列表url去爬取详情页资源,这样设计的理由:

1、在开发的过程中防止爬虫出现问题,大量请求到对方服务器,造成对方服务器过载而宕机。虽然说互联网的资源大家都有平等共享的权利,但是我们开发爬虫的时候也要注意职业操守,尽可能不要给对方服务器造成损失,如果后果很严重的话可能要被请去喝茶的,切记!切记!切记!

2、保持到本地的资源文件,对于下一步操作可以省略网络请求的那一环境,可以让你爬虫的速度更快。

3、整个过程做成异步操作进行解耦,如果在爬取列表页后马上去爬取详情页,整个过程任何一个环境出现问题,需要整个程序排查。

ps: 可以进一步优化,把列表页的整个内容都保存到本地,然后依次加载本地页面即可访问到详情页。

3、编码阶段

方便确定后,我们还是采用Python的Scrapy框架来做爬虫。

首先是环境搭建,我们用虚拟环境来构建python的运行环境。

其次:构建两个spider,一个是爬取列表数据,一个是爬取详情数据。

列表spider主要是把列表页的链接保存到一个allUrl.txt的文件中,方便后续详情页爬取。

class myspider(scrapy.Spider):    name = 'msp'    domain = 'https://www.XXXXXXX.com'    def start_requests(self):        urls = ['/html/gndy/dyzz/index.html']        for url in urls:            yield scrapy.Request(url=self.domain+url, callback=self.pagelist)    def pagelist(self, response):        select = response.xpath('//*[@id="header"]/div/div[3]/div[6]/div[2]/div[2]/div[2]/div/select').get()        # 所有分页的链接        pages = Selector(text=select).css("option").xpath("@value").getall()        curr_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))        file_path = os.path.join(curr_dir, 'pages/allUrl.txt')        with open(file_path,'w') as f:            for page in pages:                f.write(self.domain + page+"\n")

详情页spider主要是加载本地的列表数据文件,然后加载列表数据进行详情页的爬取。

class DetailSpider(scrapy.Spider):    domain = "https://www.XXXXXXX.com"    name = 'dmsp'    def start_requests(self):        curr_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))        file_path = os.path.join(curr_dir, 'pages/allUrl.txt')        start_urls = []        with open(file_path, 'r') as f:            urls = f.readlines()            for url in urls:                start_urls.append(url[0:-1])        currUrl = start_urls[22]        yield SplashRequest(url=currUrl, callback=self.parseList, args={'wait': 10},endpoint='render.html')    def parseList(self,response):        # logging.info("parseList response: %s ", response.text)        urlSel = response.xpath('//div[@class="co_content8"]/ul//a').getall()        detailUrls = []        for url in urlSel:            obj = {}            obj['url'] = self.domain + Selector(text=url).xpath('//@href').get()            obj['title'] = Selector(text=url).xpath('//text()').get()            detailUrls.append(obj)        logger.info("detailUrls: %s ",detailUrls)        for detailUrl in detailUrls:            logger.info("当前url: %s",detailUrl['url'])            yield SplashRequest(url=detailUrl['url'], callback=self.parseDetail,args={'wait': 10},endpoint='render.html')        # yield SplashRequest(url=detailUrls[0]['url'], callback=self.parseDetail,args={'wait': 10},endpoint='render.html')    def parseDetail(self,response):        image_urls = []        title = response.xpath('//div[@class="title_all"]//h1/text()').get()        ul = response.xpath("//div[@class='co_content8']//ul")        cover = ul.xpath("//div[@id='Zoom']/img[1]/@src").get()        screenshots = ul.xpath("//div[@id='Zoom']/img[2]/@src").get()        image_urls.append(cover)        image_urls.append(screenshots)        zoom = ul.xpath(".//div[@id='Zoom']/text()").getall()        magnet = response.xpath("//div[@id='downlist']//a/text()").get()        _list =  [x.strip() for x in zoom ]        _list1 =  [x for x in _list if x != '' ]        _list2 = [x.replace('\u3000','aaa') for x in _list1]        logging.info("_list2: %s ", _list2)        item = MyspiderItem()        item['image_urls'] = image_urls        item['title'] = title #标题        import datetime        item['id_uuid'] = genUUid()        item['createtime'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") #更新时间        _protagonist_index = 0        _introduction_index = 0        for _item in _list2:            if _item.find('◎译') != -1:                item['movie_name_zh'] = self.splitList(_item)            elif _item.find('◎片aaaaaa名') != -1:                item['movie_name_en'] = self.splitList(_item)            elif _item.find('◎年') != -1:                item['movie_year'] = self.splitList(_item)            elif _item.find('◎产') != -1:                item['movie_places'] = self.splitList(_item)            elif _item.find('◎类') != -1:                item['movie_type'] = self.splitList(_item)            elif _item.find('◎语') != -1:                item['movie_lanage'] = self.splitList(_item)            elif _item.find('◎字') != -1:                item['movie_subtitle'] = self.splitList(_item)            elif _item.find('◎上映日期') != -1:                item['release_date'] = self.splitList(_item)            elif _item.find('◎文件格式') != -1:                item['file_form'] = self.splitList(_item)            elif _item.find('◎视频尺寸') != -1:                item['video_size'] = self.splitList(_item)            elif _item.find('◎文件大小') != -1:                item['file_size'] = self.splitList(_item)            elif _item.find('◎片aaaaaa长') != -1:                item['movie_time'] = self.splitList(_item)            elif _item.find('◎导') != -1:                item['direct'] = self.splitList(_item)            elif _item.find('◎主') != -1:                item['protagonist'] = self.splitList(_item)                _protagonist_index = _list2.index(_item)            elif _item.find('◎简') != -1:                _introduction_index = _list2.index(_item)        item['isDownload'] = 0        protagonist = item['protagonist']        for po in _list2[_protagonist_index+1:_introduction_index]:            protagonist += "," + po        item['protagonist'] = protagonist        item['introduction'] = _list2[_introduction_index+1]        item['downloadUrl'] = magnet        logger.info("item: %s ", item)        yield item    def splitList(self,item):        return item.split("aaa")[-1]

由于此网站做了反爬机制,导致爬取的过程中偶尔会只返回一个js文件,所以这里老夫在docker容器里面跑了一个Splash镜像,实际上爬虫访问的页面是Splash返回的页面。

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值