কীভাবে কীওয়ার্ড এবং ফিল্টার সামগ্রীর ব্যবহার করে এমন একটি সি এল আই ওয়েব স্পাইডার তৈরি করব?


10

আমি আমার নিবন্ধগুলি অবহিত (অপ্রচলিত) সাহিত্যের ফোরাম ই- বনেটনেটের মধ্যে খুঁজে পেতে চাই । ফোরামের কিছু মডিউল অক্ষম রয়েছে এবং আমি তাদের লেখকের নিবন্ধের তালিকা পেতে পারি না। এছাড়াও সাইটটি গুগল, ইয়ানডেক্স ইত্যাদি হিসাবে অনুসন্ধান ইঞ্জিনগুলির দ্বারা সূচিযুক্ত নয়

আমার সমস্ত নিবন্ধ সন্ধানের একমাত্র উপায় হ'ল সাইটের আর্কাইভ পৃষ্ঠাটি খুলুন (চিত্র 1)। তারপরে আমাকে অবশ্যই নির্দিষ্ট বছর এবং মাস নির্বাচন করতে হবে - যেমন জানুয়ারী ২০১৩ (চিত্র 1) .1 এবং তারপরে আমার অবশ্যই প্রতিটি নিবন্ধ (চিত্র 2) পরিদর্শন করতে হবে শুরুর দিকে আমার ডাকনামটি লেখা আছে কিনা - Pa4080 (চিত্র .3 )। তবে কয়েক হাজার নিবন্ধ আছে।

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

আমি অনুসরণ হিসাবে কয়েকটি বিষয় পড়েছি, তবে সমাধানগুলির কোনওটিই আমার প্রয়োজনগুলির সাথে খাপ খায় না:

আমি আমার নিজস্ব সমাধান পোস্ট করব । তবে আমার জন্য আকর্ষণীয়: এই কাজটি সমাধান করার জন্য আরও কি মার্জিত কোনও উপায় আছে?

উত্তর:


3

script.py:

#!/usr/bin/python3
from urllib.parse import urljoin
import json

import bs4
import click
import aiohttp
import asyncio
import async_timeout


BASE_URL = 'http://e-bane.net'


async def fetch(session, url):
    try:
        with async_timeout.timeout(20):
            async with session.get(url) as response:
                return await response.text()
    except asyncio.TimeoutError as e:
        print('[{}]{}'.format('timeout error', url))
        with async_timeout.timeout(20):
            async with session.get(url) as response:
                return await response.text()


async def get_result(user):
    target_url = 'http://e-bane.net/modules.php?name=Stories_Archive'
    res = []
    async with aiohttp.ClientSession() as session:
        html = await fetch(session, target_url)
        html_soup = bs4.BeautifulSoup(html, 'html.parser')
        date_module_links = parse_date_module_links(html_soup)
        for dm_link in date_module_links:
            html = await fetch(session, dm_link)
            html_soup = bs4.BeautifulSoup(html, 'html.parser')
            thread_links = parse_thread_links(html_soup)
            print('[{}]{}'.format(len(thread_links), dm_link))
            for t_link in thread_links:
                thread_html = await fetch(session, t_link)
                t_html_soup = bs4.BeautifulSoup(thread_html, 'html.parser')
                if is_article_match(t_html_soup, user):
                    print('[v]{}'.format(t_link))
                    # to get main article, uncomment below code
                    # res.append(get_main_article(t_html_soup))
                    # code below is used to get thread link
                    res.append(t_link)
                else:
                    print('[x]{}'.format(t_link))

        return res


def parse_date_module_links(page):
    a_tags = page.select('ul li a')
    hrefs = a_tags = [x.get('href') for x in a_tags]
    return [urljoin(BASE_URL, x) for x in hrefs]


def parse_thread_links(page):
    a_tags = page.select('table table  tr  td > a')
    hrefs = a_tags = [x.get('href') for x in a_tags]
    # filter href with 'file=article'
    valid_hrefs = [x for x in hrefs if 'file=article' in x]
    return [urljoin(BASE_URL, x) for x in valid_hrefs]


def is_article_match(page, user):
    main_article = get_main_article(page)
    return main_article.text.startswith(user)


def get_main_article(page):
    td_tags = page.select('table table td.row1')
    td_tag = td_tags[4]
    return td_tag


@click.command()
@click.argument('user')
@click.option('--output-filename', default='out.json', help='Output filename.')
def main(user, output_filename):
    loop = asyncio.get_event_loop()
    res = loop.run_until_complete(get_result(user))
    # if you want to return main article, convert html soup into text
    # text_res = [x.text for x in res]
    # else just put res on text_res
    text_res = res
    with open(output_filename, 'w') as f:
        json.dump(text_res, f)


if __name__ == '__main__':
    main()

requirement.txt:

aiohttp>=2.3.7
beautifulsoup4>=4.6.0
click>=6.7

এখানে স্ক্রিপ্টের পাইথন 3 সংস্করণ রয়েছে (উবুন্টু 17.10 তে পাইথন 3.5 তে পরীক্ষা করা হয়েছে )।

ব্যবহারবিধি:

  • এটি ব্যবহার করতে ফাইলগুলিতে দুটি কোড রাখুন। উদাহরণস্বরূপ কোড ফাইল script.pyএবং প্যাকেজ ফাইলটি requirement.txt
  • চালান pip install -r requirement.txt
  • উদাহরণ হিসাবে স্ক্রিপ্ট চালান python3 script.py pa4080

এটি বেশ কয়েকটি গ্রন্থাগার ব্যবহার করে:

প্রোগ্রামটি আরও বিকাশ করার জন্য প্রয়োজনীয় বিষয়গুলি (প্রয়োজনীয় প্যাকেজের ডক ব্যতীত):

  • পাইথন গ্রন্থাগার: অ্যাসিনসিও, জসন এবং urllib.parse
  • সিএসএস নির্বাচক ( এমডিএন ওয়েব ডক্স ), এছাড়াও কিছু এইচটিএমএল। এই নিবন্ধটির মতো আপনার ব্রাউজারে সিএসএস নির্বাচনকারী কীভাবে ব্যবহার করবেন তাও দেখুন

কিভাবে এটা কাজ করে:

  • প্রথমে আমি একটি সাধারণ এইচটিএমএল ডাউনলোডার তৈরি করি। এটি আইওএইচটিপি ডকিতে দেওয়া নমুনা থেকে পরিবর্তিত সংস্করণ।
  • এর পরে সাধারণ কমান্ড লাইন পার্সার তৈরি করা যা ব্যবহারকারী নাম এবং আউটপুট ফাইলের নাম গ্রহণ করে।
  • থ্রেড লিঙ্ক এবং প্রধান নিবন্ধের জন্য পার্সার তৈরি করুন। পিডিবি এবং সাধারণ ইউআরএল ম্যানিপুলেশন ব্যবহার করে কাজটি করা উচিত।
  • ফাংশনটি একত্রিত করুন এবং মূল নিবন্ধটি জসন এ রাখুন, যাতে অন্যান্য প্রোগ্রাম পরে এটি প্রক্রিয়া করতে পারে।

কিছু ধারণা যাতে এটি আরও বিকাশ করা যায়

  • আরেকটি সাবকম্যান্ড তৈরি করুন যা তারিখ মডিউলটির লিঙ্কটি গ্রহণ করে: এটি তারিখের মডিউলটিকে তার নিজস্ব ফাংশনে পার্স করার জন্য এবং নতুন সাবকোমন্ডের সাথে একত্রিত করার পদ্ধতিটি পৃথক করে করা যেতে পারে।
  • তারিখের মডিউল লিঙ্কটি ক্যাচিং করা হচ্ছে: থ্রেডগুলির লিঙ্ক পাওয়ার পরে ক্যাশে জেসন ফাইল তৈরি করুন। সুতরাং প্রোগ্রামটির আবার লিঙ্কটি বিশ্লেষণ করতে হবে না। বা এমনকি মেলে না এমনকি পুরো থ্রেডের মূল নিবন্ধটিকেও ক্যাশে করুন

এটি সর্বাধিক মার্জিত উত্তর নয়, তবে আমি মনে করি এটি উত্তর ব্যবহারের চেয়ে ভাল।

  • এটি পাইথন ব্যবহার করে যার অর্থ এটি ক্রস প্ল্যাটফর্ম ব্যবহার করা যেতে পারে।
  • সাধারণ ইনস্টলেশন, সমস্ত প্রয়োজনীয় প্যাকেজ পিপ ব্যবহার করে ইনস্টল করা যেতে পারে
  • এটি আরও বিকাশিত হতে পারে, আরও পাঠযোগ্য প্রোগ্রাম, সহজতর এটি বিকাশ করা যায়।
  • এটি কেবল 13 মিনিটের জন্য ব্যাশ স্ক্রিপ্টের মতো একই কাজ করে ।

ঠিক আছে, আমি কয়েকটি মডিউল ইনস্টল sudo apt install python3-bs4 python3-click python3-aiohttp python3-asyncকরতে পেরেছি : কিন্তু আমি খুঁজে পাচ্ছি না - কোন প্যাকেজটি async_timeoutএসেছে?
pa4080

@ pa4080 আমি পাইপ দিয়ে ইনস্টল করব যাতে এটি আইওএইচটিপি সহ অন্তর্ভুক্ত থাকে। প্রথম 2 ফাংশনের অংশগুলি এখানে এওআইওটিটিপি.ড্রেডহেডসকস.আইও / এএন / স্টেবল সংশোধিত হয়েছে । এছাড়াও আমি নির্দেশ যোগ প্রয়োজনীয় প্যাকেজটি ইনস্টল করতে হবে
Dan

আমি সফলভাবে পিপ ব্যবহার করে মডিউলটি ইনস্টল করেছি। তবে অন্য কিছু ত্রুটি উপস্থিত হয়েছে: paste.ubuntu.com/26311694 । দয়া করে আমাকে যখন
পিঞ্জ করুন

@ Pa4080, আমি আপনার ত্রুটিটি প্রতিলিপি করতে পারি না, তাই আনতে ফাংশনটি সহজ করি। পার্শ্ব প্রতিক্রিয়া যে প্রোগ্রাম যদি দ্বিতীয় পুনরায় চেষ্টা কাজ করছে না ত্রুটি নিক্ষেপ পারে
ড্যান

1
মূল কনসটি হ'ল আমি কেবল উবুন্টু 17.10 এ স্ক্রিপ্টটি সফলভাবে চালাতে সক্ষম হয়েছি। তবে এটি আমার বাশ স্ক্রিপ্টের চেয়ে 5 গুণ বেশি দ্রুত, তাই আমি এই উত্তরটি গ্রহণ করার সিদ্ধান্ত নিয়েছি।
pa4080

10

এই টাস্কটি সমাধান করার জন্য আমি পরবর্তী সাধারণ বাশ স্ক্রিপ্ট তৈরি করেছি যা মূলত সিএলআই সরঞ্জাম ব্যবহার করে wget

#!/bin/bash

TARGET_URL='http://e-bane.net/modules.php?name=Stories_Archive'
KEY_WORDS=('pa4080' 's0ther')
MAP_FILE='url.map'
OUT_FILE='url.list'

get_url_map() {
    # Use 'wget' as spider and output the result into a file (and stdout) 
    wget --spider --force-html -r -l2 "${TARGET_URL}" 2>&1 | grep '^--' | awk '{ print $3 }' | tee -a "$MAP_FILE"
}

filter_url_map() {
    # Apply some filters to the $MAP_FILE and keep only the URLs, that contain 'article&sid'
    uniq "$MAP_FILE" | grep -v '\.\(css\|js\|png\|gif\|jpg\|txt\)$' | grep 'article&sid' | sort -u > "${MAP_FILE}.uniq"
    mv "${MAP_FILE}.uniq" "$MAP_FILE"
    printf '\n# -----\nThe number of the pages to be scanned: %s\n' "$(cat "$MAP_FILE" | wc -l)"
}

get_key_urls() {
    counter=1
    # Do this for each line in the $MAP_FILE
    while IFS= read -r URL; do
        # For each $KEY_WORD in $KEY_WORDS
        for KEY_WORD in "${KEY_WORDS[@]}"; do
            # Check if the $KEY_WORD exists within the content of the page, if it is true echo the particular $URL into the $OUT_FILE
            if [[ ! -z "$(wget -qO- "${URL}" | grep -io "${KEY_WORD}" | head -n1)" ]]; then
                echo "${URL}" | tee -a "$OUT_FILE"
                printf '%s\t%s\n' "${KEY_WORD}" "YES"
            fi
        done
        printf 'Progress: %s\r' "$counter"; ((counter++))
    done < "$MAP_FILE"
}

# Call the functions
get_url_map
filter_url_map
get_key_urls

স্ক্রিপ্টের তিনটি ফাংশন রয়েছে:

  • প্রথম ফাংশন get_url_map()ব্যবহার wgetহিসাবে --spider(যার মানে এটা শুধু চেক করবে যে পেজ আছে) এবং রিকার্সিভ তৈরি করবে -rURL টি $MAP_FILEএর $TARGET_URLগভীরতা স্তর সঙ্গে -l2। (আর একটি উদাহরণ এখানে পাওয়া যাবে: ওয়েবসাইটকে পিডিএফে রূপান্তর করুন )। বর্তমান ক্ষেত্রে $MAP_FILEএটিতে প্রায় 20 000 ইউআরএল রয়েছে।

  • দ্বিতীয় ফাংশনটি filter_url_map()এর বিষয়বস্তু সহজ করবে $MAP_FILE। এই ক্ষেত্রে আমরা কেবল লাইন (URL) প্রয়োজন যে স্ট্রিং ধারণ সালে article&sidতারা 3000. আরও আইডিয়ার চলেছেন এখানে পাওয়া যেতে পারে: কিভাবে একটি টেক্সট ফাইল লাইনের থেকে নির্দিষ্ট শব্দ দূর করবেন?

  • তৃতীয় ফাংশনটি প্রতিটি URL এর সামগ্রী আউটপুট get_key_urls()করতে wget -qO-(কমান্ড হিসাবে curl- উদাহরণ হিসাবে ) ব্যবহার করবে $MAP_FILEএবং এর মধ্যে যে কোনওটির সন্ধান করার চেষ্টা $KEY_WORDSকরবে। যদি কোন $KEY_WORDSকোন বিশেষ URL- এর বিষয়বস্তু মধ্যে প্রতিষ্ঠিত, যে URL- এ সংরক্ষণ করা হবে $OUT_FILE

কাজের প্রক্রিয়া চলাকালীন স্ক্রিপ্টের আউটপুটটি এটি পরবর্তী চিত্রের মতো দেখায়। দুটি কীওয়ার্ড এবং 42 মিনিটের মধ্যে কেবল একটি কীওয়ার্ড অনুসন্ধান করা হলে এটি শেষ করতে প্রায় 63 মিনিট সময় লাগে ।

এখানে চিত্র বর্ণনা লিখুন


1

@ কারেলের সরবরাহ করা এই উত্তরের ভিত্তিতে আমি আমার স্ক্রিপ্টটি পুনরায় তৈরি করেছি । এখন স্ক্রিপ্ট পরিবর্তে ব্যবহার করে । ফলস্বরূপ এটি দ্রুততর হয়ে ওঠে।lynxwget

বর্তমান সংস্করণটি 15 মিনিটের জন্য একই কাজ করে যখন দুটি অনুসন্ধানের কীওয়ার্ড থাকে এবং আমরা কেবলমাত্র একটি কীওয়ার্ড অনুসন্ধান করি তবে 8 মিনিটের জন্য। এটি @ এডান দ্বারা প্রদত্ত পাইথন সমাধানের চেয়ে দ্রুত ।

এছাড়াও lynxল্যাটিনবিহীন অক্ষরগুলির হ্যান্ডলিংয়ের আরও ভাল সরবরাহ করে।

#!/bin/bash

TARGET_URL='http://e-bane.net/modules.php?name=Stories_Archive'
KEY_WORDS=('pa4080')  # KEY_WORDS=('word' 'some short sentence')
MAP_FILE='url.map'
OUT_FILE='url.list'

get_url_map() {
    # Use 'lynx' as spider and output the result into a file 
    lynx -dump "${TARGET_URL}" | awk '/http/{print $2}' | uniq -u > "$MAP_FILE"
    while IFS= read -r target_url; do lynx -dump "${target_url}" | awk '/http/{print $2}' | uniq -u >> "${MAP_FILE}.full"; done < "$MAP_FILE"
    mv "${MAP_FILE}.full" "$MAP_FILE"
}

filter_url_map() {
    # Apply some filters to the $MAP_FILE and keep only the URLs, that contain 'article&sid'
    uniq "$MAP_FILE" | grep -v '\.\(css\|js\|png\|gif\|jpg\|txt\)$' | grep 'article&sid' | sort -u > "${MAP_FILE}.uniq"
    mv "${MAP_FILE}.uniq" "$MAP_FILE"
    printf '\n# -----\nThe number of the pages to be scanned: %s\n' "$(cat "$MAP_FILE" | wc -l)"
}

get_key_urls() {
    counter=1
    # Do this for each line in the $MAP_FILE
    while IFS= read -r URL; do
        # For each $KEY_WORD in $KEY_WORDS
        for KEY_WORD in "${KEY_WORDS[@]}"; do
            # Check if the $KEY_WORD exists within the content of the page, if it is true echo the particular $URL into the $OUT_FILE
            if [[ ! -z "$(lynx -dump -nolist "${URL}" | grep -io "${KEY_WORD}" | head -n1)" ]]; then
                echo "${URL}" | tee -a "$OUT_FILE"
                printf '%s\t%s\n' "${KEY_WORD}" "YES"
            fi
        done
        printf 'Progress: %s\r' "$counter"; ((counter++))
    done < "$MAP_FILE"
}

# Call the functions
get_url_map
filter_url_map
get_key_urls
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.