Python Crawler and JS Reverse Engineering Notes

website·Indexed 29 days ago

https://vuepress-notes-delta.vercel.app

A comprehensive technical guide covering Python3 fundamentals, network programming, and web scraping. It includes detailed sections on the Scrapy and Feapder frameworks, data extraction using BeautifulSoup and lxml, and advanced JavaScript reverse engineering, including symmetric/asymmetric encryption (AES, DES, SM series), webpack analysis, OB obfuscation, and environment emulation (JSVMP).

Tokens
120K
Snippets
553
Records
658
Agent score
72%

What's inside Python Crawler Notes

  1. Overview of Babel AST toolset

    Babel provides a suite of libraries to handle JavaScript AST transformations:

    • @babel/core: The core compiler providing the compilation API.
    • @babel/parser: Parses JavaScript code into an AST (JSON structure).
    • @babel/traverse: Used to traverse and modify nodes within the AST.
    • @babel/generator: Converts an AST back into JavaScript source code.
    • @babel/types: Used to validate node types and build new AST nodes.
    npm install @babel/core --save-dev
  2. Overview of Asymmetric Encryption (RSA)

    Asymmetric encryption uses a pair of keys: a public key and a private key. Data encrypted with the public key can only be decrypted by the corresponding private key, and vice versa. Common algorithms include RSA and DSA. Unlike symmetric encryption, the private key is kept by the receiver and never transmitted over the network, enhancing security. However, asymmetric encryption is computationally more complex and slower than symmetric encryption. It is also commonly used for digital signatures.
  3. Overview of Symmetric Encryption Algorithms

    Symmetric encryption uses the same key for both encryption and decryption. Both the sender and receiver must possess the identical key and algorithm. Common symmetric algorithms include:

    • DES (Data Encryption Standard): Uses a 56-bit key. Now largely deprecated due to the short key length.
    • AES (Advanced Encryption Standard): Supports 128, 192, and 256-bit keys. Currently widely used due to higher security and complexity for attackers.
    • 3DES (Triple DES): An evolution of DES.
    • RC4: A stream cipher.
  4. Overview of SM Chinese National Cryptography Algorithms

    The SM (ShangMi) series consists of commercial cryptography standards used in China. The most common algorithms encountered in web development and reverse engineering are:

    • SM2: An asymmetric public-key encryption algorithm based on Elliptic Curve Cryptography (ECC). It is designed to replace RSA, offering higher security with smaller key sizes (256-bit SM2 is stronger than RSA-2048) and faster key generation.
    • SM3: A cryptographic hash function used for integrity verification, comparable in security and efficiency to SHA-256.
    • SM4: A symmetric block cipher used for data encryption, replacing DES/AES. It uses a 128-bit key and block size with a 32-round non-linear iterative structure.
  5. Introduction to JavaScript Hooking for Debugging

    Hooking is a technique used to intercept function calls before they are executed. By redefining a function, a developer can modify its behavior, log arguments, or trigger a debugger statement to inspect the call stack. This is particularly useful for locating data encryption logic when standard DOM or XHR breakpoints are too broad or deep in the call stack. For a hook to work, the hook script must be executed in the same scope as the function being hooked.
  6. Overview of Web Crawling Concepts

    A web crawler (also known as a web spider or bot) is a program that simulates a browser to send network requests and automatically fetch internet information based on specific rules. Essentially, any action a browser (client) can perform can be replicated by a crawler. Crawlers are generally categorized into two types: General Crawlers (e.g., search engine bots like Baidu) and Focused Crawlers (targeted at specific websites). While many languages supporting HTTP(S) requests (C++, Java, PHP, JavaScript) can be used, Python is the most common choice due to its development efficiency.
  7. Understand JavaScript Prototypes and Prototype Chains for Environment Mimicking

    In JavaScript, every object has an implicit prototype (__proto__) that points to the explicit prototype (prototype) of the class that created it. When accessing a property or method, if it is not found on the object itself, JavaScript searches up the prototype chain. This mechanism is critical when mimicking browser environments (like navigator or document) because detection scripts often check if a method exists on the object or its prototype chain using hasOwnProperty or Object.getOwnPropertyDescriptor.
  8. Implement an Amazon product scraper with proxy support

    This implementation demonstrates a professional scraping architecture using Python. It utilizes Queue for managing URLs and data, retrying for handling request failures, and pymysql for bulk data storage. The scraper follows a three-step pipeline: extracting category links, discovering product detail URLs through pagination, and parsing final product details (title and price). It includes commented-out logic for integrating a paid proxy API to avoid IP blocking.
    import pymysql
    import requests
    import retrying
    from lxml import etree
    from queue import Queue
    from feapder.network.user_agent import get
    
    class AmazonShop:
        def __init__(self):
            # Database connection
            self.db = pymysql.connect(host='localhost', user='root', password='root', db='py_spider')
            self.cursor = self.db.cursor()
            
            # Target API and Headers
            self.amazon_api = 'https://www.amazon.cn/nav/ajax/hamburgerMainContent...'
            self.headers = {
                "Referer": "https://www.amazon.cn",
                "User-Agent": "Mozilla/5.0...",
                "X-Requested-With": "XMLHttpRequest",
            }
    
            # Queues for pipeline management
            self.classify_url_queue = Queue() # Category URLs
            self.detail_url_queue = Queue()    # Product detail URLs
            self.shop_info_queue = Queue()    # Final product data
    
        def create_table(self):
            sql = """
                create table if not exists amazon_shop(
                    id int primary key auto_increment,
                    price varchar(255) not null,
                    title varchar(255) not null,
                    goods_url varchar(255) not null
                );
            """
            self.cursor.execute(sql)
    
        @retrying.retry(stop_max_attempt_number=3)
        def get_shop_data(self, url):
            # Dynamic User-Agent rotation
            self.headers['User-Agent'] = get()
            # To use proxies, uncomment: 
            # proxies = {'http': 'http://' + ip, 'https': 'https://' + ip}
            # response = requests.get(url, headers=self.headers, proxies=proxies, timeout=2)
            response = requests.get(url, headers=self.headers)
            return response
    
        def parse_shop_info(self):
            while True:
                goods_data = self.detail_url_queue.get()
                goods_url = 'https://www.amazon.cn' + goods_data['detail_href']
                try:
                    response = self.get_shop_data(goods_url)
                    tree = etree.HTML(response.text)
                    
                    # Extract Title
                    title = tree.xpath('//div[@id="centerCol"]//h1/span/text()')[0] if tree.xpath('//div[@id="centerCol"]//h1/span/text()') else tree.xpath('//title/text()')[0]
                    
                    # Extract Price
                    if tree.xpath('//div[@id="centerCol"]//div[@id="apex_desktop"]//span[@class="a-price-whole"]/text()'):
                        price = "¥" + tree.xpath('//div[@id="centerCol"]//div[@id="apex_desktop"]//span[@class="a-price-whole"]/text()')[0]
                    else:
                        price = '-'.join(tree.xpath('//td[@class="a-span12"]//span[@class="a-offscreen"]/text()'))
    
                    self.shop_info_queue.put((title.strip(), price, goods_url))
                except Exception as e:
                    print('Error:', e)
                finally:
                    self.detail_url_queue.task_done()
    
        def save_shop_info(self):
            while True:
                info_list = []
                for _ in range(30): # Batch insert 30 records
                    info = self.shop_info_queue.get()
                    info_list.append((0,) + info)
                    self.shop_info_queue.task_done()
    
                sql = "insert into amazon_shop(id, price, title, goods_url) values (%s, %s, %s, %s);"
                self.cursor.executemany(sql, info_list)
  9. Understand the role of AST in the V8 JavaScript Engine

    The V8 engine processes JavaScript code through several distinct stages to execute it. The AST (Abstract Syntax Tree) serves as the intermediate representation of the source code, allowing the engine to perform semantic interpretation and execution. The pipeline is as follows:

    1. Parse: Converts JavaScript source code into an AST.
    2. Ignition: The interpreter converts the AST into bytecode.
    3. TurboFan: The compiler optimizes bytecode into executable machine code based on collected information.
    4. Orinoco: The garbage collection phase that reclaims unused memory.
  10. Implement distributed crawling with scrapy-redis

    The scrapy-redis library enables a distributed architecture where multiple Scrapy processes (Slaver nodes) share a single Redis database (Master node). The Master node handles URL fingerprint deduplication, request distribution, and data storage, while Slaver nodes execute the crawling logic and submit new requests back to the Master.

    To implement a distributed spider, you must inherit from RedisSpider and define a redis_key which specifies the Redis key containing the initial start URLs.

    from scrapy_redis.spiders import RedisSpider
    
    class MyDistributedSpider(RedisSpider):
        name = "my_spider"
        # The key in Redis where start URLs are stored
        redis_key = 'my_spider:start_urls'
    
        def parse(self, response, **kwargs):
            # Crawling logic here
            pass
  11. Understand Sekiro RPC Core Concepts

    The Sekiro RPC framework allows a client (like a browser) to register functions that can be invoked remotely via a server. Key concepts include:

    • group: A business logic group. Multiple clients can register under one group, and a group can host multiple Actions.
    • clientId: A unique identifier for a specific device/client, enabling load balancing and group control.
    • SekiroClient: The service provider (e.g., a browser) that connects to the server and executes the requested actions.
    • registerAction: The method used to define a specific remote interface/function within a group.
    • resolve: The callback used to send the result of the execution back to the server.
    • request: The data object sent from the server to the client, containing parameters for the action.