猫眼电影—流浪地球爬虫(1)

再来一波流浪地球的爬虫,不过这次爬的是猫眼电影。而且这次不再是用scrapy而是用最常规的方法requests
同时这里还要详细讲几个别的问题。

  • 什么是Ajax
  • 如何进行反爬
  • 如何储存到MongoDB中

首先,常规操作进行猫眼电影的网址进行分析。但是我们发现在其网页端,它的评论往往没有那么多。
此时我们用的是猫眼电影的手机端url:http://m.maoyan.com/movie/248906/morecomments?_v_=yes

猫眼页面.png

大家可以往下滑,发现在页面没有跳转的情况下,内容就加载出来了,可以知道这里用的是Ajax加载的方式。
那么什么是Ajax呢?

Ajax

Ajax,全称为Asynchronous JavaScript and XML,即异步的JavaScript和XML。它不是一门编程语言,而是利用JavaScript在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。

对于传统的网页,如果想更新其内容,那么必须要刷新整个页面,但有了Ajax,便可以在页面不被全部刷新的情况下更新其内容。在这个过程中,页面实际上是在后台与服务器进行了数据交互,获取到数据之后,再利用JavaScript改变网页,这样网页内容就会更新了。

Ajax实现原理

Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。
具体大家可以自行Google哦。

Ajax分析方法

那么我们在刷新,获取信息的时候,我们看到的url是没有变化的,而是一次次的Ajax请求渲染了网页。那么我们应该去哪里查看呢?
当然是右键——检查,借助开发者工具进行检查。

检查.png

不过这一次我们关注的就不是Elements选项卡了,而是Network选项卡。
我们进行切换并且刷新,就能获得如图所示的信息:

Network.png

那么在这里:


XHR.png

选择XHR,筛选出来的就是Ajax请求啦。
我们选择开头有comments.json的条目,在它的Request Headers可以看到比传统的请求头中多了一项X-Requested-With: superagent,而superagent是一种轻量级的Ajax请求方式。

随后,我们点击Preview选项卡,可以看到网页是json格式,而chrome已经帮我们解析出来了

json.png

可以看到在data下,有我们需要的东西。
此时,想要获取这些内容非常容易了,就像是获取字典的值一样。

res = requests.get(url,timeout,headers=self.headers)
comments = res.json()['data']['comments']

这样我们就能获取评论数据,进行下一步提取了。

同时我们在Headers里可以看到真实的url:http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=0&limit=15&ts=0&level=2&type=3,并且请求方式是get
那么我们多点击几个,观察url就会发现,其中变化的只有参数offset,并且是每15进行累加。

代码

直接上代码吧。

import requests
import time
from datetime import datetime
from pymongo import MongoClient
from lxml import etree
import random


class maoyan():
    def __init__(self):
        self.headers = {
                'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36                       (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
                'cookie':"_lxsdk_cuid=163f4936fa628-0651e9953b7cba-791238-144000-163f4936fa7c8; v=3; iuuid=A83BE960AA7E11E8B6349B995F5768EC558368427A114227869310FFD50B50A1; webp=true; ci=185%2C%E5%98%89%E5%85%B4; _lx_utm=utm_source%3Dgoogle%26utm_medium%3Dorganic; _lxsdk=438345E032A511E9BDC5F9F05A760829F59E3BE1237E422D9B95E24FCA63731A; __mta=254523319.1528816694943.1535432227454.1550402539437.7; _lxsdk_s=168fb2aa1e2-1c1-2d8-2a8%7C%7C24",
                }
    #反爬
    def get_comments(self,i,timeout,proxy=None):
        page = i*15
        num_retries = 6
        url = 'http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset={}&lim                 it=15&ts=1550476464599&level=2&type=3'.format(page)
        
        if proxy == None:
            try:
                res = requests.get(url,timeout,headers=self.headers)
                
            except:
                if num_retries>0:
                    time.sleep(10)
                    print('网页获取出错,10s后将获取倒数第{}次'.format(num_retries))
                    res= requests.get(url,timeout,headers=self.headers)
                    num_retries -= 1
                    
                else:
                    print('开始使用代理')
                    time.sleep(10)
                    proxy = self.get_ip
                    res = requests.get(url,timeout,proxies=proxy,headers=self.headers)
                    
        else:
            try:
                proxy = self.get_ip
                res = requests.get(url,timeout,proxies=proxy,headers=self.headers)
                
            except:
                if num_retries > 0:
                    time.sleep(10)
                    proxy = self.get_ip
                    res = requests.get(url,timeout,proxies=proxy,headers=self.headers)
                else:
                    print('代理失败,取消代理')
                    res = requests.get(url,timeout,headers=self.headers)

        
        comments = res.json()['data']['comments']
        return comments
    #保存到MongoDB中
     def save_data(self,comment):
        client = MongoClient()
        db = client['maoyan']
        collection = db['lldq']
        try:
            if collection.insert_one(comment):
                print('Saved to Mongo')
        except:
            print('无法保存')
    #获取代理       
    def get_ip(self):
        url = 'http://www.xiladaili.com/http/'
        response = requests.get(url)
        t = response.text
        html = etree.HTML(t)
        result = html.xpath("//table[@class='fl-table']/tbody/tr[{}]/td[1]/text()".format(random.randint(1,50)))
        proxy = {
                'https':str(result[0])
                }
        return proxy

if __name__ == '__main__':
    for i in range(0,500):
        if i%5 == 0:
            time.sleep(1)
            my = maoyan()
            d = my.get_comments(i,timeout=3)
            my.parse_comments(d,i)
        
    
            
        

反爬

我在get_comments()函数里写了一大段,其实是为了更好的反爬。
首先就是请求头,写上了heasersuser-agentcookie,这是为了让网站认为这是一个人发送的请求,而不是机器。
其次,这里多加了一个代理proxies

def get_ip(self):
        url = 'http://www.xiladaili.com/http/'
        response = requests.get(url)
        
        t = response.text
        html = etree.HTML(t)
        result = html.xpath("//table[@class='fl-table']/tbody/tr[{}]/td[1]/text()".format(random.randint(1,50)))
        proxy = {
                'https':str(result[0])
                }
        return proxy

代理是通过一个免费网站中获得的,随机取得一个ip,用于requests
虽然代码很长,但是简单,就是有点繁琐。
同时在请求一个url后,经常会time.sleep(),否则,请求的太过于频繁,就会被封的。
最后requests.get中的timeout参数可以设定等待连接的秒数,超过时间,就会抛出异常。

储存

这一次,我们将数据存入MongoDB

准备工作

具体自行搜索啦,怎么安装,下载。

连接MongoDB

连接MongoDB时,我们需要使用的是,PyMongo库里面的MongoClient。一般来说,传入MongoDB的ip和端口即可。

import pymongo import MongoClient

client = pymongo.MongoClient(host='localhost',port=27017)

这样就可以创建MoongoDB的连接对象啦。
当然我们也可以换种方式:

client = MongoClient('mongodb://localhost:27017/')

指定数据库

MongoDB中可以建立多个数据库,接下来我们需要指定操作哪个数据库,在这里,我们以建立maoyan为例:

db = client['maoyan']

或者

db = client.maoyan

指定集合

在每个数据库里又有许多集合(collection),它们类似于关系型数据库中的表。

下一步就是要指定操作的集合,同样我们建立名为lldq的集合:

collection = db['lldq']

或者

collection = db.lldq

插入数据

此时,我们可以插入数据了。
一般数据以字典的形式表示,比如我们如果要获取我们想要的id,性别,评论,分数,等等:

comment = {'content': com['content'], 'gender': com['gender'],
'id': com['id'],
'nick': com['nick'],
'replyCount': com['replyCount'], 
'score': com['score'],
'time': com['time'], 
'upCount': com['upCount'],
'userId': com['userId'], 
'userLevel': com['userLevel']
}

诸如这种形式。
我们可以使用insert_one()insert_many()方法来插入单条和多条记录

collection.insert_one(comment)

如果你是用的是insert_many(),就要将数据以列表的形式传递。
比如,你有两个字典,分别为dic1,dic2,要存储到mongodb

collection.insert_many([dic1,dic2])

可视化工具

最后储存了一大堆,可是怎么看呢?
这里推荐Robo 3T,官方网站,三大平台都支持,下载链接。
另外,还有一个简单易用的可视化工具——Studio 3T,它同样具有方便的图形化管理界面,官方网站,同样支持三大平台,下载链接。

预告

接下俩,会讲讲,可视化函数,以及对这次爬取到的数据的处理。
最后请大家批评指正!

你可能感兴趣的:(猫眼电影—流浪地球爬虫(1))