多线程撒网式爬取全国地图各地区矿点信息

今天给大家带来一个全国各地矿区信息爬取的爬虫。

目标地址(推荐使用谷歌浏览器打开):http://ngac.org.cn/Kuangchandi/index.html

打开这个链接后我们会看到如下画面:

真夜猫.JPG

点击右上角的属性查询,再点击地图上这些红红绿绿的点,就会弹出此片矿区相关属性。

网页数据抓取分析:

这个网页上的数据交互是通过提交我们点击鼠标的位置的坐标为参数,来实现数据请求的。我们无法从获取他的有效坐标,所以我们这里只能使用撒网式抓取。因为post提交的两个变化的数据为x,y;也就是我们的鼠标坐标。所以我们这里使用两个嵌套循环,将(100,100,800,800)这个范围的长方形里面的所有坐标点全部依次搞成参数进行请求,再进行数据的筛选过滤,因为数据量太多,我们这里使用多线程。

需导入的库:

import requests
from fake_useragent import UserAgent
from queue import Queue
import threading
import time

数据抓取函数:

ua=UserAgent(use_cache_server=False)
infos=[]
class get_infos(threading.Thread):
    def __init__(self,zb_queue,*args,**kwargs):
        super(get_infos, self).__init__(*args, **kwargs)
        self.zb_queue=zb_queue

    def run(self):
        while True:
            if self.zb_queue.empty():
                break
            data=self.zb_queue.get()
            self.spider(data)

    def spider(self,data):
        try:
            url = "http://ngac.org.cn/Kuangchandi/mapinfonew.ashx"
            response=requests.post(url,headers={'User-Agent':ua.random,},data=data)
            if response.text !='{"OBJECTID":"nothing"}':
                if response.text in infos:
                    pass
                else:
                    print(response.text)
                    infos.append(response.text)

        except:
            pass

这里我们使用多线程爬取,提高我们的运行效率。我们的代码是从队列中提取已经传入xy坐标的data。然后进行post请求,再进行过滤。因为有的坐标点没有数据,有的坐标点的数据是重复的,比如说我点上面地图上的一个圆点,我们点坐标(200,200)是他,点坐标(200,201)也是它,返回的数据都一样。所以我们这里利用判断列表是否存在这个值来进行去重。

控制主函数:

def main():
    zb_queue=Queue(2000000)
    for x in range(100,800):
        for y in range(100,800):
            data={'url': 'http://219.142.81.85/arcgis/services/0refield/MapServer/WMSServer?  request=getfeatureinfo&transparent=true&format=xml%2Fhtml&version=1.1.1&layers=0&query_layers=0&srs=EPSG%3A4326&X='+str(x)+'&Y='+str(y)+'&height=758&width=703&bbox=72.95344531249998%2C2.736753125000007%2C134.74055468749998%2C69.357846875',}
            zb_queue.put(data)
    print("data:over")
    for i in range(10):
        t=get_infos(zb_queue)
        t.start()
        time.sleep(0.02)
if __name__ == '__main__':
    main()

这里思路就是先将我们每次请求所需的每个点的data数据放进一个队列。然后将队列传入我们的类,进行多线程操作。这里加延迟的原因是,防止两个线程同时查看列表里是否存在相同的值,同时发现列表中无相同值,然后打印相同的结果,我们这里加上一点延迟,避免这种情况。

运行结果:

真夜猫.JPG

从我展示的部分信息上可以看出,我们这里已经成功的获取到了我们所需的信息。学会的朋友可以自己去试试。

你可能感兴趣的:(多线程撒网式爬取全国地图各地区矿点信息)