中國裁決文書網(wǎng)爬蟲

之所以爬這個網(wǎng)站,是因為一位朋友也在爬,而且推薦了一下給我,說作為練手很不錯,于是我就是爬了,于是這網(wǎng)站寫了我差不多五天,寫得我真是嘔心瀝血啊,好了,先看網(wǎng)站要提取哪些數(shù)據(jù),這次要爬的是廣告合同糾紛案件

Paste_Image.png

箭頭是要爬取的內(nèi)容,為案件的主要內(nèi)容,以及每個案件的wensuhID類型,時候個post請求,需要上傳的data是下面這個,可以在chrome上看到

Paste_Image.png

好的開干,先看代碼框架

Paste_Image.png

先看數(shù)據(jù)庫mogo_data的代碼,很多操作要用到這里的代碼

from pymongo import MongoClient,errors
from _datetime import datetime,timedelta


class mogo_queue():
    OUTSTANDING = 1  ##初始狀態(tài)
    PROCESSING = 2  ##正在爬取狀態(tài)
    COMPLETE = 3  #爬取完成的狀態(tài)
    def __init__(self,db,collection,timeout=60):
        self.client = MongoClient()
        self.database =self.client[db]#鏈接數(shù)據(jù)庫
        self.db = self.database[collection]#鏈接數(shù)據(jù)庫里面這個表
        self.timeout = timeout
    def __bool__(self):
        """
        這個函數(shù),我的理解是如果下面的表達(dá)為真,則整個類為真

        $ne的意思是不匹配
        """
        record = self.db.find_one(
            {'status': {'$ne': self.COMPLETE}}
        )
        return True if record else False
    def find_proxy(self):
        proxy_list=[]#用來接收從數(shù)據(jù)庫查找到的所有代理
        for i in self.db.find():
            proxy = i['proxy']
            proxy_list.append(proxy)
        return proxy_list
    def select_data(self):#一旦取走一個data,data的狀態(tài)就要改變,防止多進(jìn)程重復(fù)提取
        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):#這個函數(shù)是把超時的沒有爬取成功的data的
        # 狀態(tài)改變,跟之前爬宜搜的功能一樣,防止漏抓
        """這個函數(shù)是重置狀態(tài)$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狀態(tài)', record['data'])
    def complete(self, id):
        """這個函數(shù)是更新已完成的URL完成"""
        self.db.update({'_id': str(id)}, {'$set':{'status':self.COMPLETE}})
        print('data的status狀態(tài)轉(zhuǎn)為完成')
    def insert_data(self,data,id):
        try:
            self.db.insert({'_id':id,'data':data})
            print(data,'插入成功')
        except errors.DuplicateKeyError as e:#對于重復(fù)的ip不能插入
            print(id,'已經(jīng)存在隊列中')
    def push_data(self,page):#把需要提交的data裝進(jìn)數(shù)據(jù)庫
        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, '已經(jīng)存在隊列中')
    def status_setting(self):#這函數(shù),如果data都抓取成功了一般不啟用.....
        record = self.db.find({'status': self.PROCESSING})  # 找到所有狀態(tài)為2的代理,就是之前抓取過的
        for i in record:
            #print(i)
            id = i["_id"]
                        
            self.db.update({'_id': id}, {'$set': {'status': self.OUTSTANDING}})  # 該狀態(tài)為1,重新抓取
            
            print(i['data'], '更改成功')

這是push_data的代碼,很簡單幾行,就是把需要提取的data存進(jìn)數(shù)據(jù)庫

from  mogo_data import mogo_queue
data_queue= mogo_queue('wenshu','data_index')
data_queue.push_data(357)#把需要爬取的data傳進(jìn)去

好了,到了爬蟲主程序,這個真的寫得我要死要死的

import re
import time
import requests
import threading#用于創(chuàng)建線程
import json
from bs4 import BeautifulSoup
from  mogo_data import mogo_queue
import time
import random
import multiprocessing#用于創(chuàng)建多進(jìn)程的
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',
                 ]#這些請求頭都是我測試過非常高效的,
                 #而且這網(wǎng)站很奇葩,主要是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')  # 實例化,儲存文書數(shù)據(jù)的數(shù)據(jù)庫
    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('隊列沒有數(shù)據(jù)')
                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]#提取網(wǎng)頁返回
                    length = len(html.text)
                    print(proxie,headers)
                    print(html.text)
                    if status_number==str(200):#判斷網(wǎng)頁是否正常返回
                        if int(length) >=int(1000):#判斷網(wǎng)頁返回的是否是正常內(nèi)容
                            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)  # 清理數(shù)據(jù)里面的符號,然后轉(zhuǎn)化成字典
                                    one_case = json.loads(the_case)  # 轉(zhuǎn)化成字典
                                    wensuh_data = {
                                            '案號': one_case['案號'] if one_case['案號'] else '該文書沒有此項數(shù)據(jù)',
                                            '案件類型': one_case['案件類型'] if one_case['案件類型'] else '該文書沒有此項數(shù)據(jù)',
                                            '法院名稱': one_case['法院名稱'] if one_case['法院名稱'] else '該文書沒有此項數(shù)據(jù)',
                                            '審判程序': one_case['審判程序'] if one_case['審判程序'] else '該文書沒有此項數(shù)據(jù)',
                                            '案件名稱': one_case['案件名稱'] if one_case['案件名稱'] else '該文書沒有此項數(shù)據(jù)',
                                            '裁判日期': one_case['裁判日期'] if one_case['裁判日期'] else '該文書沒有此項數(shù)據(jù)',
                                            '裁判要旨段原文': one_case['裁判要旨段原文'] if one_case['裁判要旨段原文'] else '該文書沒有此項數(shù)據(jù)',
                                            #'文書ID': one_case['文書ID'] if one_case['文書ID'] else '該文書沒有此項數(shù)據(jù)',
                                        }  # 有些文書不一樣,所以要在字典里面添加判斷語句
                                    id=one_case['文書ID']

                                    writ_data.insert_data(wensuh_data,id)



                                data_queue.complete(data['Index'])#數(shù)據(jù)插入成功調(diào)用這個函數(shù)

                            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__函數(shù)的作用,為真則
                代表我們MongoDB隊列里面還有data沒有提交進(jìn)行抓取或者
                threads 為真,都代表我們還沒下載完成,程序就會繼續(xù)執(zhí)行
                """
        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)  ##創(chuàng)建線程
            thread.setDaemon(True)  ##設(shè)置守護(hù)線程
            thread.start()  ##啟動線程
            threads.append(thread)  ##添加進(jìn)線程隊列
        time.sleep(10)

def process_crawler():
    process = []
    num_cpus = multiprocessing.cpu_count()
    print('將會啟動進(jìn)程數(shù)為:', int(num_cpus)-6)
    for i in range(int(num_cpus)-6):
        p = multiprocessing.Process(target=catch_wensuh_judge)  ##創(chuàng)建進(jìn)程
        p.start()  ##啟動進(jìn)程
        process.append(p)  ##添加進(jìn)進(jìn)程隊列
        for p in process:
            p.join()  ##等待進(jìn)程隊列里面的進(jìn)程結(jié)束

if __name__ == "__main__":
    data_queue.status_setting()#啟用了這個函數(shù)將data狀態(tài)由2改為1,
    # 是因為我之前抓取失敗了,要重新改了再來.....
    process_crawler()

最后說一下,成功抓取的案件只有2000左右,但是我看他網(wǎng)頁上的介紹,說廣告合同糾紛是有7000個案件的,于是傻乎乎的構(gòu)造了300多個data,只有100個抓取成功了,于是我又調(diào)節(jié)了很久我的爬蟲,是不是代理問題啊,是不是主程序問題啊,用了很多可信的IP和請求頭測試,最后發(fā)現(xiàn)這網(wǎng)站能抓取的本來就只有100個data,超出之后的,從101頁開始,返回的都是空集,是None,真是日了狗....可是我不服啊,不可能啊明明寫著7000個案件啊,于是我想手點(diǎn)到101頁,結(jié)果在30多頁的時候就提醒你,精確度不夠,沒有數(shù)據(jù)返回,提醒我進(jìn)行精確查找...........于是我深深懷疑這方式能提取到的數(shù)據(jù)真的就只有這么多了,最后上兩者效果圖

Paste_Image.png

數(shù)據(jù)庫圖

Paste_Image.png

寫得我見到這個網(wǎng)站都惡心了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容