使用borb库RegularExpressionTextExtraction提取PDF文本时触发AssertionError(矩形宽度需非负)问题求助
Hey Erik, sorry you're stuck with this annoying error while trying to pull the "Cited by" mentions from your PDF. Let's walk through what's going on and how we can fix it.
First, let's recap your setup: you adapted code from borb's regex text extraction examples, pointing it at your PDF file, but when running the script, it crashes with an AssertionError: A Rectangle must have a non-negative width. This happens because some glyphs in your PDF (likely those in the boxes you mentioned) have a bounding box with a negative width, which borb's internal code doesn't expect.
Here's your code for reference:
#!chapter_005/src/snippet_006.py import typing from borb.pdf import Document from borb.pdf import PDF from borb.toolkit import RegularExpressionTextExtraction teonderzoekenpdf = "Jim.pdf" zoekstring = 'Cited by' def main(): # read the Document # fmt: off print("Stap 2") doc: typing.Optional[Document] = None l: RegularExpressionTextExtraction = RegularExpressionTextExtraction(zoekstring) with open(teonderzoekenpdf, "rb") as in_file_handle: print("Stap 3") doc = PDF.loads(in_file_handle, [l]) print("Stap 3,5") # fmt: on # check whether we have read a Document print("Stap 4") assert doc is not None print("Stap 5") # print matching groups for i, m in enumerate(l.get_matches()[0]): print("Stap 6") print("%d %s" % (i, m.group(0))) #for r in m.get_bounding_boxes(): #print( # "\t%f %f %f %f" % (r.get_x(), r.get_y(), r.get_width(), r.get_height()) #) if __name__ == "__main__": print("Stap 1") main()
And the error you're seeing:
PS C:\Users\Erik\Desktop\Strings_uit_pdf> c:; cd 'c:\Users\Erik\Desktop\Strings_uit_pdf'; & 'c:\Python312\python.exe' 'c:\Users\Erik\.vscode\extensions\ms-python.debugpy-2024.14.0-win32-x64\bundled\libs\debugpy\adapter/../..\debugpy\launcher' '51988' '--' 'c:\Users\Erik\Desktop\Strings_uit_pdf\stringsuitpdf.py' Stap 1 Stap 2 Stap 3 Traceback (most recent call last): File "c:\Users\Erik\Desktop\Strings_uit_pdf\stringsuitpdf.py", line 56, in <module> main() File "c:\Users\Erik\Desktop\Strings_uit_pdf\stringsuitpdf.py", line 29, in main doc = PDF.loads(in_file_handle, [l]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\pdf\pdf.py", line 85, in loads document: Document = ReadAnyObjectTransformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\reference\xref_transformer.py", line 305, in transform trailer = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\object\dictionary_transformer.py", line 69, in transform v = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\reference\reference_transformer.py", line 169, in transform transformed_referenced_object = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\page\root_dictionary_transformer.py", line 112, in transform transformed_root_dictionary = t.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\object\dictionary_transformer.py", line 69, in transform v = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\reference\reference_transformer.py", line 169, in transform transformed_referenced_object = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\object\dictionary_transformer.py", line 69, in transform v = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\object\array_transformer.py", line 69, in transform object_to_transform[i] = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\reference\reference_transformer.py", line 169, in transform transformed_referenced_object = self.get_root_transformer().transform( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\any_object_transformer.py", line 113, in transform return super().transform( ^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\transformer.py", line 149, in transform out = h.transform( ^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\io\read\page\page_dictionary_transformer.py", line 129, in transform CanvasStreamProcessor(page_out, canvas, []).read( File "c:\Python312\Lib\site-packages\borb\pdf\canvas\canvas_stream_processor.py", line 277, in read raise e File "c:\Python312\Lib\site-packages\borb\pdf\canvas\canvas_stream_processor.py", line 271, in read operator.invoke(self, operands, event_listeners) File "c:\Python312\Lib\site-packages\borb\pdf\canvas\operator\text\show_text_with_glyph_positioning.py", line 84, in invoke l._event_occurred(tri) File "c:\Python312\Lib\site-packages\borb\toolkit\text\regular_expression_text_extraction.py", line 326, in _event_occurred self._render_text(event) File "c:\Python312\Lib\site-packages\borb\toolkit\text\regular_expression_text_extraction.py", line 338, in _render_text for e in text_render_info.split_on_glyphs(): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\pdf\canvas\event\chunk_of_text_render_event.py", line 177, in split_on_glyphs e._baseline_bounding_box = Rectangle( ^^^^^^^^^^ File "c:\Python312\Lib\site-packages\borb\pdf\canvas\geometry\rectangle.py", line 30, in __init__ assert width >= 0, "A Rectangle must have a non-negative width." ^^^^^^^^^^ AssertionError: A Rectangle must have a non-negative width.
How to Fix This:
Let's try these solutions in order:
Update borb to the latest version
This is the easiest first step. The borb team might have already fixed this edge case in a newer release. Run this command in your terminal:pip install --upgrade borbThen re-run your script to see if the error goes away.
Monkey-patch the Rectangle class to handle negative widths
If updating doesn't work, we can modify how borb's Rectangle class handles width values to avoid the assertion. Add this code at the very top of your script (before importing any borb modules):from borb.pdf.canvas.geometry.rectangle import Rectangle # Save the original initialization method original_rect_init = Rectangle.__init__ def patched_rect_init(self, x: float, y: float, width: float, height: float): # Convert negative width/height to positive to bypass the assertion width = abs(width) height = abs(height) original_rect_init(self, x, y, width, height) # Replace the original __init__ with our patched version Rectangle.__init__ = patched_rect_initThis will make sure any negative width values are turned positive, so the assertion doesn't trigger.
Get page numbers for your matches
Once the error is fixed, you can modify your loop to include the page number for each match. Theget_matches()method returns a list where each index corresponds to a page (starting from 0), so adding 1 gives you the actual page number:# Print matching groups with page numbers for page_index, page_matches in enumerate(l.get_matches()): print(f"--- Page {page_index + 1} ---") for match_index, match in enumerate(page_matches): print(f"{match_index + 1}: {match.group(0)}")
If All Else Fails:
If none of these fixes work, your PDF might have some non-standard elements that borb struggles with. You could try alternative PDF text extraction libraries like pdfplumber or PyPDF2, but since you're set on using borb, the above patches should get you past the error.
Hope this helps you get those "Cited by" mentions extracted successfully!
备注:内容来源于stack exchange,提问作者ErikDB

