中国裁决文书网爬虫

作者: 蜗牛仔 | 来源:发表于2017-01-25 16:03 被阅读1821次

    之所以爬这个网站,是因为一位朋友也在爬,而且推荐了一下给我,说作为练手很不错,于是我就是爬了,于是这网站写了我差不多五天,写得我真是呕心沥血啊,好了,先看网站要提取哪些数据,这次要爬的是广告合同纠纷案件

    Paste_Image.png

    箭头是要爬取的内容,为案件的主要内容,以及每个案件的wensuhID类型,时候个post请求,需要上传的data是下面这个,可以在chrome上看到

    Paste_Image.png

    好的开干,先看代码框架

    Paste_Image.png

    先看数据库mogo_data的代码,很多操作要用到这里的代码

    from pymongo import MongoClient,errors
    from _datetime import datetime,timedelta
    
    
    class mogo_queue():
        OUTSTANDING = 1  ##初始状态
        PROCESSING = 2  ##正在爬取状态
        COMPLETE = 3  #爬取完成的状态
        def __init__(self,db,collection,timeout=60):
            self.client = MongoClient()
            self.database =self.client[db]#链接数据库
            self.db = self.database[collection]#链接数据库里面这个表
            self.timeout = timeout
        def __bool__(self):
            """
            这个函数,我的理解是如果下面的表达为真,则整个类为真
    
            $ne的意思是不匹配
            """
            record = self.db.find_one(
                {'status': {'$ne': self.COMPLETE}}
            )
            return True if record else False
        def find_proxy(self):
            proxy_list=[]#用来接收从数据库查找到的所有代理
            for i in self.db.find():
                proxy = i['proxy']
                proxy_list.append(proxy)
            return proxy_list
        def select_data(self):#一旦取走一个data,data的状态就要改变,防止多进程重复提取
            record = self.db.find_and_modify(
                query={'status': self.OUTSTANDING},
                update={'$set': {'status': self.PROCESSING, 'timestamp': datetime.now()}}
            )
            if record:
                return record['data']
            else:
                self.repair()
                raise KeyError
        def repair(self):#这个函数是把超时的没有爬取成功的data的
            # 状态改变,跟之前爬宜搜的功能一样,防止漏抓
            """这个函数是重置状态$lt是比较"""
            record = self.db.find_and_modify(
                query={
                    'timestamp': {'$lt': datetime.now() - timedelta(seconds=self.timeout)},
                    'status': {'$ne': self.COMPLETE}
                },
                update={'$set': {'status': self.OUTSTANDING}}
            )
            if record:
                print('重置data状态', record['data'])
        def complete(self, id):
            """这个函数是更新已完成的URL完成"""
            self.db.update({'_id': str(id)}, {'$set':{'status':self.COMPLETE}})
            print('data的status状态转为完成')
        def insert_data(self,data,id):
            try:
                self.db.insert({'_id':id,'data':data})
                print(data,'插入成功')
            except errors.DuplicateKeyError as e:#对于重复的ip不能插入
                print(id,'已经存在队列中')
        def push_data(self,page):#把需要提交的data装进数据库
            for i in range(1, page):
                data = {
                    'Param': '案件类型:民事案件,案由:广告合同纠纷',
                    'Index': str(i),
                    'Page': '20',
                    'Order': '法院层级',
                    'Direction': 'asc',
                }
                try :
                    self.db.insert({'_id':data['Index'],'data':data,'status':self.OUTSTANDING})
                    print(data,'插入成功')
                except errors.DuplicateKeyError as e:
                    print(data, '已经存在队列中')
        def status_setting(self):#这函数,如果data都抓取成功了一般不启用.....
            record = self.db.find({'status': self.PROCESSING})  # 找到所有状态为2的代理,就是之前抓取过的
            for i in record:
                #print(i)
                id = i["_id"]
                            
                self.db.update({'_id': id}, {'$set': {'status': self.OUTSTANDING}})  # 该状态为1,重新抓取
                
                print(i['data'], '更改成功')
    

    这是push_data的代码,很简单几行,就是把需要提取的data存进数据库

    from  mogo_data import mogo_queue
    data_queue= mogo_queue('wenshu','data_index')
    data_queue.push_data(357)#把需要爬取的data传进去
    

    好了,到了爬虫主程序,这个真的写得我要死要死的

    import re
    import time
    import requests
    import threading#用于创建线程
    import json
    from bs4 import BeautifulSoup
    from  mogo_data import mogo_queue
    import time
    import random
    import multiprocessing#用于创建多进程的
    from pymongo import MongoClient
    
    user_agent_list=['Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1',
                     'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11',
                     'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
                     'Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1',
                     'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36',
                     'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.9.2.1000 Chrome/39.0.2146.0 Safari/537.36',
                     #'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24',
                     'Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11',
                     'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3',
                     'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3',
                     'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/532.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/532.3',
                     'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5',
                     #'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3',
                     'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
                     ]#这些请求头都是我测试过非常高效的,
                     #而且这网站很奇葩,主要是IE的请求头访问都会出错
    
    data_queue = mogo_queue('wenshu', 'data_index_two')  # 实例化需要提交的data
    url='http://wenshu.court.gov.cn/List/ListContent?'
    def catch_wensuh_judge(max_threads=3):
        writ_data = mogo_queue('China_judge_writ', 'advertisement_writ')  # 实例化,储存文书数据的数据库
        ip_queue = mogo_queue('ip_database', 'proxy_collection')  # 实例化代理池
        def wenshu_crawler():
            while True:
                try:
                    data=data_queue.select_data()#选择data
                    print(data)
                except KeyError:
                    print('队列没有数据')
                    break
                else:
                    Agent = random.choice(user_agent_list)
                    proxie_list = ip_queue.find_proxy()#提取代理
                    proxy = random.choice(proxie_list)
                    headers = {
                        'User-Agent': Agent,
                        'Referer': 'http://wenshu.court.gov.cn/List/List?sorttype=1&conditions=searchWord+2+AJLX++%E6%A1%88%E4%BB%B6%E7%B1%BB%E5%9E%8B:%E6%B0%91%E4%BA%8B%E6%A1%88%E4%BB%B6',
                         #'Referer': 'http://wenshu.court.gov.cn/List/List?sorttype=1&conditions=searchWord+2+AJLX++%E6%A1%88%E4%BB%B6%E7%B1%BB%E5%9E%8B:%E6%B0%91%E4%BA%8B%E6%A1%88%E4%BB%B6'
                    }
                    proxie = {
                        'http': proxy.strip(),
                        'https': proxy.strip()
                    }
                    time.sleep(5)
                    try:
                        html = requests.post(url, data=data, proxies=proxie, headers=headers, timeout=10)  # headers=headers
                        status_number = re.findall(r'\d\d\d', str(html))[0]#提取网页返回
                        length = len(html.text)
                        print(proxie,headers)
                        print(html.text)
                        if status_number==str(200):#判断网页是否正常返回
                            if int(length) >=int(1000):#判断网页返回的是否是正常内容
                                try:
                                    content = BeautifulSoup(html.text, 'lxml')
                                    we_data = re.findall(r'\[(.*)\]', str(content), re.S)
                                    all_data = re.sub(r'\\', '', str(we_data))
                                    all_case = all_data.split('}')[1:-1]
                                    for i in all_case:
                                        info = i + '}'
                                        the_case = info.replace(',', '', 1)  # 清理数据里面的符号,然后转化成字典
                                        one_case = json.loads(the_case)  # 转化成字典
                                        wensuh_data = {
                                                '案号': one_case['案号'] if one_case['案号'] else '该文书没有此项数据',
                                                '案件类型': one_case['案件类型'] if one_case['案件类型'] else '该文书没有此项数据',
                                                '法院名称': one_case['法院名称'] if one_case['法院名称'] else '该文书没有此项数据',
                                                '审判程序': one_case['审判程序'] if one_case['审判程序'] else '该文书没有此项数据',
                                                '案件名称': one_case['案件名称'] if one_case['案件名称'] else '该文书没有此项数据',
                                                '裁判日期': one_case['裁判日期'] if one_case['裁判日期'] else '该文书没有此项数据',
                                                '裁判要旨段原文': one_case['裁判要旨段原文'] if one_case['裁判要旨段原文'] else '该文书没有此项数据',
                                                #'文书ID': one_case['文书ID'] if one_case['文书ID'] else '该文书没有此项数据',
                                            }  # 有些文书不一样,所以要在字典里面添加判断语句
                                        id=one_case['文书ID']
    
                                        writ_data.insert_data(wensuh_data,id)
    
    
    
                                    data_queue.complete(data['Index'])#数据插入成功调用这个函数
    
                                except:
                                    continue#失败了再来
                            else:
                                time.sleep(2)
                                continue#失败了再来
                        else:
                            time.sleep(2)
                            continue#失败了再来
                    except:
                        time.sleep(1)
                        continue#失败了再来
        threads = []
        while threads or data_queue:
            """
                    这儿crawl_queue用上了,就是我们__bool__函数的作用,为真则
                    代表我们MongoDB队列里面还有data没有提交进行抓取或者
                    threads 为真,都代表我们还没下载完成,程序就会继续执行
                    """
            for thread in threads:
                if not thread.is_alive():  ##is_alive是判断是否为空,不是空则在队列中删掉
                    threads.remove(thread)
            while len(threads) < max_threads:  ##线程池中的线程少于max_threads 
                thread = threading.Thread(target=wenshu_crawler)  ##创建线程
                thread.setDaemon(True)  ##设置守护线程
                thread.start()  ##启动线程
                threads.append(thread)  ##添加进线程队列
            time.sleep(10)
    
    def process_crawler():
        process = []
        num_cpus = multiprocessing.cpu_count()
        print('将会启动进程数为:', int(num_cpus)-6)
        for i in range(int(num_cpus)-6):
            p = multiprocessing.Process(target=catch_wensuh_judge)  ##创建进程
            p.start()  ##启动进程
            process.append(p)  ##添加进进程队列
            for p in process:
                p.join()  ##等待进程队列里面的进程结束
    
    if __name__ == "__main__":
        data_queue.status_setting()#启用了这个函数将data状态由2改为1,
        # 是因为我之前抓取失败了,要重新改了再来.....
        process_crawler()
    
    

    最后说一下,成功抓取的案件只有2000左右,但是我看他网页上的介绍,说广告合同纠纷是有7000个案件的,于是傻乎乎的构造了300多个data,只有100个抓取成功了,于是我又调节了很久我的爬虫,是不是代理问题啊,是不是主程序问题啊,用了很多可信的IP和请求头测试,最后发现这网站能抓取的本来就只有100个data,超出之后的,从101页开始,返回的都是空集,是None,真是日了狗....可是我不服啊,不可能啊明明写着7000个案件啊,于是我想手点到101页,结果在30多页的时候就提醒你,精确度不够,没有数据返回,提醒我进行精确查找...........于是我深深怀疑这方式能提取到的数据真的就只有这么多了,最后上两者效果图

    Paste_Image.png

    数据库图

    Paste_Image.png

    写得我见到这个网站都恶心了

    相关文章

      网友评论

      • 子不语_98e1:可以加你qq吗,膜拜大神,我也是要爬这网站,而且刚上手😂
      • 未满_3cd3:兄弟,你这套方法好像不管用啦。。。现在网站新增加了一个guid 和 number 和 vl5x,加个好友可以吗?qq:362250358
        蜗牛仔:@未满_3cd3 可以的,810833835
        未满_3cd3:@蜗牛仔 能加你个qq好友吗?
        蜗牛仔:@未满_3cd3 的确不不管用啦,网站结构变了,我现在已经没有涉猎这个网站了,毕竟没有啥动力了哈
      • 吉洛德:很好
        谢谢
        未满_3cd3:你抓下来了吗?现在网站抓不到了呀,post需要增加的参数变多了
      • Samsanny:作者你好,在应用你的爬虫的时候遇到了一些问题,运行mogo_data没有结果,运行spider显示将会启动进程数为: -2,运行push_data显示'Param': '案件类型:民事案件,案由:广告合同纠纷', 'Index': '356', 'Page': '20', 'Order': '法院层级', 'Direction': 'asc'} 已经存在队列中等一系列数据,但是并没有出现演示中的裁判书内容等关键数据:mask: (本人小小白,如果问了一些特别愚蠢的问题还希望作者大大谅解)求解决方法,谢谢:blush:
        蜗牛仔:@Samsanny 是这样的兄台,网站结构变了啦,由于没有需求,我也没在鼓捣这个网站啦,之前的代码是完全不行了的,现在天天在公司撸社交平台的数据,以后有空再来研究研究这个网站吧:smile:
      • 818734b915ed:不是只有2000条啊兄弟,换个排序方式还可以抓出来数据的
        818734b915ed:@蜗牛仔 兄弟,他这个数确实是100页之后返回的都是空
        818734b915ed:@蜗牛仔 就是例如,他post的数据里不是有个order吗,你按裁判日期的正倒序分别抓一次,数据会多不少
        蜗牛仔:@818734b915ed 这位兄台,可以说具体一点吗,万分感谢
      • 养蚕人:作者你好,我也在爬这个网站!我想做的是把上面的pdf批量下载下来···然后我用的是post,却一直不成功···可以请教一下吗,谢谢了
        蜗牛仔:@养蚕者 有用代理吗,useagent有伪造吗
      • d457c870b553:你好,刚想入门Python 爬虫,能否给点建议,比如是不是该先把基本语法摸透。再去找些小项目自己爬爬,但我感觉我现在看到这些都好晕的。
        有时候没什么耐心看下去
        d457c870b553:@蜗牛仔 好的,谢谢!也希望都能坚持下去:smile:
        蜗牛仔:@湖哥会飞翔 你好,我是0基础开始学Python爬虫的,我可以说一下我是如何开始的,但不保证是最有效的。我当时0基础报名了网易那个0基础四周学会爬虫的课程,然后发现一节课都听不懂,接着就去慕课网补充了HTML css JavaScript等知识,然后这个基础爬虫课程可以啃下来了,接着就可以学别的课程了,当然Python基础语法要懂一点,但是这个不难,在实践中联系才最重要,希望对你有帮助。我也是刚毕业半年在努力学习啊,跟你一样
      • black_crow:厉害厉害,比我之前做的高明多了,要像你学习
        蜗牛仔:@black_crow 兄台,谦虚了,我们以后要互勉的

      本文标题:中国裁决文书网爬虫

      本文链接:https://www.haomeiwen.com/subject/dugtittx.html