ExtractHyperlinksFromOfficeFiles

Extracts hyperlinks from office files. Supported file types are: xlsx, docx, pptx.

python · Common Scripts

Source

import os
import zipfile
from io import BytesIO

import demistomock as demisto  # noqa: F401
import openpyxl
import pandas as pd
from CommonServerPython import *  # noqa: F401
from docx import Document
from docx.opc.constants import RELATIONSHIP_TYPE as RT
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE


def extract_hyperlinks_from_xlsx(file_path: str) -> Set:
    with zipfile.ZipFile(file_path, "r") as zf:
        xmls = [zf.read(fn) for fn in zf.infolist() if fn.filename.startswith("xl/drawings/_rels/")]

    urls = set()

    for xml_data in xmls:
        # Wrap bytes in BytesIO for compatibility with pandas 2.x
        df = pd.read_xml(BytesIO(xml_data))

        if "TargetMode" in df.columns:
            filtered_df = df.loc[df["TargetMode"].eq("External"), "Target"]
            urls |= set(filtered_df)

    wb = openpyxl.load_workbook(file_path)
    for sheet in wb:
        for row in sheet.iter_rows():
            for cell in row:
                if cell.hyperlink:
                    urls.add(cell.hyperlink.target)

    return urls


def extract_hyperlinks_from_docx(file_path: str) -> Set:
    doc = Document(file_path)
    links = set()
    for rel in doc.part.rels.values():
        if rel.reltype == RT.HYPERLINK and rel.is_external:
            links.add(rel._target)

    return links


def extract_hyperlinks_from_pptx(file_path: str) -> Set:
    prs = Presentation(file_path)
    links = set()
    for slide in prs.slides:
        for shape in slide.shapes:
            if shape.has_text_frame:
                for paragraph in shape.text_frame.paragraphs:
                    for run in paragraph.runs:
                        if run.hyperlink and run.hyperlink.address:
                            links.add(run.hyperlink.address)
            if shape.shape_type == MSO_SHAPE_TYPE.GROUP:  # pylint: disable=E1101
                group_shape = shape
                for s in group_shape.shapes:
                    if s.click_action and s.click_action.hyperlink.address:
                        links.add(s.click_action.hyperlink.address)
            elif shape.click_action and shape.click_action.hyperlink.address:
                links.add(shape.click_action.hyperlink.address)

    return links


def extract_hyperlink_by_file_type(file_name: str, file_path: str) -> CommandResults:
    if file_name.lower().endswith(".xlsx"):
        result = extract_hyperlinks_from_xlsx(file_path)
    elif file_name.lower().endswith(".docx"):
        result = extract_hyperlinks_from_docx(file_path)
    elif file_name.lower().endswith(".pptx"):
        result = extract_hyperlinks_from_pptx(file_path)
    else:
        raise ValueError("Unsupported file type. Supported types are: 'xlsx, docx, pptx'")
    if result:
        urls_str = "\n".join(result)
        hr = f"### Extracted Hyperlinks\n\n{urls_str}"
    else:
        hr = "**No hyperlinks.**"

    output = [{"URL": url, "FileName": file_name} for url in result]
    return CommandResults(
        outputs=output,
        outputs_prefix="ExtractedHyperLink",
        outputs_key_field=["URL", "FileName"],
        readable_output=hr,
        raw_response=list(result),
    )


def main():  # pragma: no cover
    try:
        entry_id = demisto.args().get("entry_id")
        file_result = demisto.getFilePath(entry_id)
        if not file_result:
            raise ValueError(f"Couldn't find entry id: {entry_id}")
        file_name = os.path.basename(file_result.get("name", ""))
        file_path = file_result.get("path")
        os.rename(f"./{file_path}", file_name)
        return_results(extract_hyperlink_by_file_type(file_name=file_name, file_path=os.path.realpath(file_name)))
    except Exception as ex:
        return_error(f"Failed to execute ExtractHyperlinksFromOfficeFiles. Error: {ex!s}")


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()

README

Extract hyperlinks from office files. Supported file types are: xlsx, docx, pptx.

Script Data


Name Description
Script Type python3
Cortex XSOAR Version 5.5.0

Inputs


Argument Name Description
entry_id The entry id of the file to extract hyperlinks from.

Outputs


Path Description Type
ExtractedHyperLink.URL The extracted hyperlinks URL. String
ExtractedHyperLink.FileName The office file that the hyperlinks extracted from. String

Script Examples

Example command

!ExtractHyperlinksFromOfficeFiles entry_id=1249@93725c86-540d-4ee4-8728-f0ab82b1cb46

Context Example

{
    "ExtractedHyperLink": {
        "FileName": "Link.docx",
        "URL": "https://www.paloaltonetworks.com/"
    }
}

Human Readable Output

Extracted hyperlinks are

https://www.paloaltonetworks.com/