Python 网络爬虫教程3

芜湖,感谢各位的支持。那么废话不多说开始我们今天的学习。

进阶篇

模拟手机应用进行抓包

前提条件是:安装Fiddler的机器,跟智能手机 在同一个网络里, 否则智能手机不能把HTTP发送到Fiddler的机器上来。

配置Fiddler, 允许"远程连接"

用Fiddler对Android应用进行抓包
  • 启动Fiddler,打开菜单栏中的 Tools > Fiddler Options,打开“Fiddler Options”对话框。

Python 网络爬虫教程3_第1张图片

  • 在Fiddler Options”对话框切换到“Connections”选项卡,然后勾选“Allow romote computers to connect”后面的复选框,然后点击“OK”按钮。

Python 网络爬虫教程3_第2张图片

  • 在本机命令行输入:ipconfig,找到本机的ip地址。

Python 网络爬虫教程3_第3张图片

  • 下面来设置Android设备上的代理服务器:

    打开android设备的“设置”->“WLAN”,找到你要连接的网络,在上面长按,然后选择“修改网络”,弹出网络设置对话框,在接下来弹出的对话框中,勾选“显示高级选项”。在接下来显示的页面中,点击“代理”,选择“手动”。

  • 在“代理”后面的输入框选择“手动”,在“代理服务器主机名”后面的输入框输入电脑的ip地址,在“代理服务器端口”后面的输入框输入8888,然后点击“保存”按钮。

    代理服务器主机名设为PC的IP,代理服务器端口设为Fiddler上配置的端口8888,点"保存"。

Python 网络爬虫教程3_第4张图片

  • 然后启动android设备中的浏览器,访问百度的首页,在fiddler中可以看到完成的请求和响应数据。

Python 网络爬虫教程3_第5张图片

用Fiddler对IOS应用进行抓包

打开IPhone, 找到你的网络连接, 打开HTTP代理, 输入Fiddler所在机器的IP地址(比如:192.168.1.104) 以及Fiddler的端口号8888

Python 网络爬虫教程3_第6张图片

  • 只能捕获HTTP,而不能捕获HTTPS的解决办法

为了让Fiddler能捕获HTTPS请求。如果你只需要截获HTTP请求, 可以忽略这一步

  • 首先要知道Fiddler所在的机器的IP地址: 假如我安装了Fiddler的机器的IP地址是:192.168.1.104
  • 打开IPhone 的Safari, 访问 http://192.168.0.52:8888, 点"FiddlerRoot certificate" 然后安装证书

    Python 网络爬虫教程3_第7张图片

Python 网络爬虫教程3_第8张图片

过证书校验

上面的设置还不能抓像招商银行、支付宝等APP的https包,因为这些APP对https证书进行了校验,还需要将Fiddler代理服务器的证书导到Android设备上才能抓这些APP的包

导入的过程:

打开浏览器,在地址栏中输入代理服务器的IP和端口,会看到一个Fiddler提供的页面:

Python 网络爬虫教程3_第9张图片

点击页面中的“FiddlerRootcertificate”链接,接着系统会弹出对话框:

Python 网络爬虫教程3_第10张图片

输入一个证书名称,然后直接点“确定”就好了。

注意

用完了, 记得把IPhone上的Fiddler代理关闭, 以免IPhone上不了网。

夜神android模拟器设置代理的方法

app开发测试为了调试方便,通常会在电脑上装一些android模拟器,开多台进行测试。调试中通常要干的一件事就是抓取,那么想要抓包,我们必须要设置代理。

夜神android模拟机设置代理的方法:

  • 点击设置,然后进入到wifi连接选项。如图1:

    Python 网络爬虫教程3_第11张图片

进入列表后,鼠标点击wifi位置,长按左键,会出现一个修改网络的弹窗,如下图:

Python 网络爬虫教程3_第12张图片

点击上图中的“修改网络”,会出现下图中的弹窗,勾选“显示高级选项”,

Python 网络爬虫教程3_第13张图片

接着一切都明了了,代理服务器主机名填写你电脑的ip就行了(window系统的话,用ipconfig查看),接着再填写端口

Python 网络爬虫教程3_第14张图片

美团App热门商圈团购采集(1)

环境:

针对美团版本5.4

Python 网络爬虫教程3_第15张图片

在tutorial项目下

新建一个spider

scrapy genspider -t basic Meituan_City meituan.com

编辑items.py

class MeituanCity(Item):
    data = Field()

编辑 Meituan_City.py

# -*- coding: utf-8 -*-
import scrapy
import json
from tutorial.items import MeituanCity
class MeituanCitySpider(scrapy.Spider):
    name = "Meituan_City"
    allowed_domains = ["meituan.com"]
    start_urls = (
        'http://api.mobile.meituan.com/group/v1/city/list?show=all',
    )
    def parse(self, response):
        data = json.loads(response.body)
        for item in data['data']:
            cityId = item['id']
            # http://api.mobile.meituan.com/group/v2/area/list?cityId=42&spatialFields=center
            url = 'http://api.meituan.com/group/v2/area/list?cityId=%s&spatialFields=center' % cityId
            print url
            yield scrapy.Request(
                url,
                callback=self.Parse_Geo,
                meta={'item': item}
            )
            break
    def Parse_Geo(self, response):
        print response.url
        data = json.loads(response.body)
        metaitem = response.meta['item']
        # 商区信息
        subareasinfo = dict()
        if 'data' in data:
            if 'subareasinfo' in data['data']:
                for item in data['data']['subareasinfo']:
                    subareasinfo[item['id']] = item
        if 'data' in data:
            if 'areasinfo' in data['data']:
                for line in data['data']['areasinfo']:
                    # 行政区
                    districtName = line['name']
                    districtId = line['id']
                    for tmp in line['subareas']:
                        # 商圈信息
                        area = subareasinfo[tmp]
                        center = area['center']
                        center = center.replace('POINT(', '').replace(')', '').split()
                        if len(center) > 1:
                            lat = center[1]
                            lng = center[0]
                        longitude = None
                        latitude = None
                        try:
                            longitude = str(int(float(lng) * 1000000))
                            latitude = str(int(float(lat) * 1000000))
                        except:
                            pass
                        Item = MeituanCity()
                        Item['data'] =dict()
                        geoItem=Item['data'] 
                        # 城市信息
                        geoItem['cityid'] = metaitem['id']
                        geoItem['cityname'] = metaitem['name']
                        # 行政区
                        geoItem['districtId'] = districtId
                        geoItem['districtName'] = districtName
                        # 商圈
                        geoItem['SubAreaId'] = area['id']
                        geoItem['secondArea'] = area['name']
                        # 经纬度
                        geoItem['longitude'] = longitude
                        geoItem['latitude'] = latitude
                        yield Item

此时运行:

scrapy runspider tutorial/spiders/Meituan_City.py

美团App热门商圈团购采集(2)

把上节内容生成的城市信息 items.json改成city_items.json作为第二部分爬虫的启动数据

添加items.py

class MeituanItem(Item):
    data = Field()

创建模板:

scrapy genspider -t basic Meituan_meishi meituan.com

添加以下代码到Meituan_meishi.py

# -*- coding: utf-8 -*-
import scrapy
import codecs
import json
from tutorial.items import MeituanItem
import re
class MeituanMeishiSpider(scrapy.Spider):
    '''
    美食团购页面信息采集
    '''
    name = "Meituan_meishi"
    allowed_domains = ["meituan.com"]
    '''
    start_urls = (
        'http://www.meituan.com/',
    )
    '''
    offset = 0
    def start_requests(self):
        file = codecs.open('city_items.json', 'r', encoding='utf-8')
        for line in file:
            item = json.loads(line)
            cityid = item['data']['cityid']
            latitude = item['data']['latitude']
            longitude= item['data']['longitude']
            lat = round(float(latitude), 6)
            lng= round(float(longitude), 6)
            url = 'http://api.mobile.meituan.com/group/v4/deal/select/city/42/cate/1?sort=defaults&mypos='+ str(lat) +'%2C'+ str(lng) +'&offset=0&limit=15'
            yield scrapy.Request(url,callback=self.parse)
            break
        file.close()
    def parse(self, response):
        '''
        数据存储以及翻页操作
        '''
        item = MeituanItem()
        data = json.loads(response.body)
        item['data']=dict()
        item['data'] = data
        yield item
        offset = re.search('offset=(\d+)',response.request.url).group(1)
        url = re.sub('offset=\d+','offset='+str(int(offset)+15),response.request.url)
        yield scrapy.Request(url,callback=self.parse)

运行:

scrapy runspider tutorial/spiders/Meituan_meishi.py

 

爬虫搜索策略

在爬虫系统中,待抓取URL队列是很重要的一部分。待抓取URL队列中的URL以什么样的顺序排列也是一个很重要的问题,因为这涉及到先抓取那个页面,后抓取哪个页面。而决定这些URL排列顺序的方法,叫做抓取策略。

1、 深度优先搜索策略(顺藤摸瓜)(Depth-First Search)

即图的深度优先遍历算法。网络爬虫会从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页,继续跟踪链接。

Python 网络爬虫教程3_第16张图片

2、 广度(宽度)优先搜索策略(Breadth First Search)

宽度优先遍历策略的基本思路是,将新下载网页中发现的链接直接插入待抓取URL队列的末尾。也就是指网络爬虫会先抓取起始网页中链接的所有网页,然后再选择其中的一个链接网页,继续抓取在此网页中链接的所有网页。

有很多研究将广度优先搜索策略应用于聚焦爬虫中。其基本思想是认为与初始URL在一定链接距离内的网页具有主题相关性的概率很大。

Python 网络爬虫教程3_第17张图片

广度优先搜索和深度优先搜索

深度优先搜索算法涉及的是堆栈

广度优先搜索涉及的是队列。

堆栈(stacks)具有后进先出(last in first out,LIFO)的特征

队列(queue)是一种具有先进先出(first in first out,LIFO)特征的线性数据结构

Python 网络爬虫教程3_第18张图片

Scrapy是以广度优先还是深度优先进行爬取的呢?

默认情况下,Scrapy使用 LIFO 队列来存储等待的请求。简单的说,就是 深度优先顺序 。深度优先对大多数情况下是更方便的。如果您想以 广度优先顺序 进行爬取,你可以设置以下的设定:

DEPTH_PRIORITY = 1
SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'

 Python 网络爬虫教程3_第19张图片

二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]

深度优先搜索算法(Depth First Search),是搜索算法的一种。是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。

当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。

如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

Python 网络爬虫教程3_第20张图片

如右图所示的二叉树:

A 是第一个访问的,然后顺序是 B、D,然后是 E。接着再是 C、F、G。

那么,怎么样才能来保证这个访问的顺序呢?

分析一下,在遍历了根结点后,就开始遍历左子树,最后才是右子树。

因此可以借助堆栈的数据结构,由于堆栈是后进先出的顺序,由此可以先将右子树压栈,然后再对左子树压栈,

这样一来,左子树结点就存在了栈顶上,因此某结点的左子树能在它的右子树遍历之前被遍历。

深度优先遍历代码片段

 

//深度优先遍历
void depthFirstSearch(Tree root){
    stack nodeStack;  //使用C++的STL标准模板库
    nodeStack.push(root);
    Node *node;
    while(!nodeStack.empty()){
        node = nodeStack.top();
        printf(format, node->data);  //遍历根结点
        nodeStack.pop();
        if(node->rchild){
            nodeStack.push(node->rchild);  //先将右子树压栈
        }
        if(node->lchild){
            nodeStack.push(node->lchild);  //再将左子树压栈
        }
    }
}

完整代码:

/**
 * 
 */
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define Element char
#define format "%c"
typedef struct Node {
    Element data;
    struct Node *lchild;
    struct Node *rchild;
} *Tree;
int index = 0;  //全局索引变量
//二叉树构造器,按先序遍历顺序构造二叉树
//无左子树或右子树用'#'表示
void treeNodeConstructor(Tree &root, Element data[]){
    Element e = data[index++];
    if(e == '#'){
        root = NULL;
    }else{
        root = (Node *)malloc(sizeof(Node));
        root->data = e;
        treeNodeConstructor(root->lchild, data);  //递归构建左子树
        treeNodeConstructor(root->rchild, data);  //递归构建右子树
    }
}
//深度优先遍历
void depthFirstSearch(Tree root){
    stack nodeStack;  //使用C++的STL标准模板库
    nodeStack.push(root);
    Node *node;
    while(!nodeStack.empty()){
        node = nodeStack.top();
        printf(format, node->data);  //遍历根结点
        nodeStack.pop();
        if(node->rchild){
            nodeStack.push(node->rchild);  //先将右子树压栈
        }
        if(node->lchild){
            nodeStack.push(node->lchild);  //再将左子树压栈
        }
    }
}
//广度优先遍历
void breadthFirstSearch(Tree root){
    queue nodeQueue;  //使用C++的STL标准模板库
    nodeQueue.push(root);
    Node *node;
    while(!nodeQueue.empty()){
        node = nodeQueue.front();
        nodeQueue.pop();
        printf(format, node->data);
        if(node->lchild){
            nodeQueue.push(node->lchild);  //先将左子树入队
        }
        if(node->rchild){
            nodeQueue.push(node->rchild);  //再将右子树入队
        }
    }
}
/**
 * 
 */
#include "binarytree.h"
int main() {
    //上图所示的二叉树先序遍历序列,其中用'#'表示结点无左子树或无右子树
    Element data[15] = {'A', 'B', 'D', '#', '#', 'E', '#', '#', 'C', 'F','#', '#', 'G', '#', '#'};
    Tree tree;
    treeNodeConstructor(tree, data);
    printf("深度优先遍历二叉树结果: ");
    depthFirstSearch(tree);
    printf("\n\n广度优先遍历二叉树结果: ");
    breadthFirstSearch(tree);
    return 0;
}

你可能感兴趣的:(python,爬虫,开发语言)