我写了一个Python脚本,以在Word文档GitHub link is here中找到断开的链接。如果要使用它,则可以转到GitHub页面,并且说明在那里。在下面,我将解释它是如何工作的以及我如何提出该解决方案。
该程序的灵感是通过帮助朋友的启发。朋友必须单击文档中的链接,以检查它们是否仍在工作。我想着自己,听起来这听起来像是可以自动化的任务。因此,我要求一些示例文档并开始测试概念。
面对这项艰巨的任务,我决定将任务分为几个步骤,找出一种方法,然后将它们拼凑在一起。
步骤1:从文本中找到链接
如果我想从文本中提取一些模式,那么弹出的第一件事就是正则表达式。它们是在文本中找到模式的一种方式,通常被开发人员认为困难和恐惧。因此,我做了任何理智的开发人员都会做的事情:在线搜索此问题,并从堆栈溢出中复制了正则正则。
正则是(https?:\/\/\S+)
,很容易理解
|正则|含义|
| http | http |
| s? | s零至一次|
| :// | ://, /代表逃脱 / |
| \ s |任何非Whitespace字符|
| + |从零到无限时间|
问题1:随后的全场也匹配
假设我有一个以链接结束的句子,例如http://chit.hashnode.com。如果我在上面的正则分析本文中,也将包括最后一个全停(。),因为它是一个非Whitespace字符。
解决方案是使用另一条正则http[s]?:\/\/[^\s]+[^.]
,在这里我们有一个[^.]
,这意味着:匹配一个字符而不是周期(。)而不是whitespace(),因此它解决了它捕获尾随周期的问题。<<<<<<<<<<<<<<<<<<<<<<< /p>
问题2:结尾具有新线字符
以前的正则是在行结尾处有一个周期的问题。但是,如果之后有一个newline字符怎么办?
知识转储:什么是新线角色
newline字符是不可见的字符,它告诉文本编辑器转到下一行。例如,假设\n
是Newline字符,I am a line.\nI am another line
将成为
I am a line.
I am another line
让我们使用网站regex101对其进行测试,当我们拥有A sentence ending in https://google.com.
时,https://google.com
将被正确捕获。
但是,在此之后,它也将被捕获,因为newline字符在[^.]
中没有排除。
当我写这篇博客文章时,我认为解决方案也是排除新线角色,从而导致了regex http[s]?:\/\/[^\s]+[^.]
,但是当我编程时,我并不明确,我想出的解决方案是用太空栏替换所有Newline字符。然后进行正则匹配,因为不再有newline字符。
问题3:不同类型的链接
第三个问题是链接,没有http
,我们的正则是从http
开始匹配的链接,但是有些链接以www
开头,甚至没有www
。
我敢肯定,更聪明的正则可以容纳这一点,但是我不想在这个阶段花太多时间,所以我只是使用python库为我做这项工作。这就是Python的美/问题,有很多库,您可以使用一个库,而不在乎它是如何实现的。
from urlextract import URLExtract
urlextracter = URLExtract()
urls = urlextracter.gen_urls(s)
步骤2检查链接
现在,我们已经提取了文本中的所有URL,我们想检查它们。
问题4:未指定协议的链接
但是记得有些链接如何从HTTP开头?我需要在它们面前添加HTTP,否则Python库请求将很难知道需要什么协议,因此我使用以下代码来实现该协议
import re
def formaturl(url):
if not re.match('(?:http|ftp|https)://', url):
return 'http://{}'.format(url)
return url
urls = [formaturl(url) for url in urls]
在这里,我尝试匹配正则(?:http|ftp|https)://
,它测试URL是否以http/ftp/https开头,如果没有,我们在其前面附加了http://
然后,我们使用列表理解在整个URL列表上进行。
实际检查链接
现在,我们进入了实际检查链接的步骤,我们使用requests
库来做到这一点。我们将requests.get()包装在一个trycatch块中,以便如果发生其他问题,该程序不会崩溃,它将简单地返回false。如果响应的状态_code不是200,那么我们也返回false,否则我们返回true。
200意味着一切都很好,因此,如果网站返回标准内容,它将返回所有内容。
def check_link(url):
print(f"checking {url}")
# Try and see if url have inherit problem
try:
response = requests.get(url)
except:
return False
# See if not 200
if not response.status_code == 200:
return False
return True
步骤3:阅读Word文档文本
现在,我有一个提取URL的函数,另一个可以检查URL的网站是否正常工作。我必须从Word文档中添加文本。
为此,我可以简单地使用Word中的保存AS功能,然后将其称为一天。这将以文本格式保存文档,我们可以使用程序读取文本文件并获得结果。
,但这意味着用户必须做更多的事情,所以我在想,可以直接使用Python读取Word Document?
答案是肯定的,因为实际上,Word文档只是zip文件。要知道我是否告诉您真相,请安装7zip并解压缩文档,您将看到以下结果。 Word文档只是一个包含许多XML文件的zip文件。
解决此问题的一种方法是将Word文档读取为zip文件,并在XML文件中找到链接。但是,由于我正在使用Python,因此我决定找到是否有任何库可以为我做到这一点。我找到了docx
,docx2txt
,docx2python
。在测试所有内容之后,我决定使用的是docx2python
,因为它提取了主要文本,标题,页脚甚至脚注。语法如下:
from docx2python import docx2python
# extract docx content
def get_text_by_docx2python(path):
text = docx2python(path).text
return text
步骤4将它们拼凑在一起
现在,难题的所有部分都在这里,现在该实现主要逻辑了,我们首先提取use_docx2python.get_text_by_docx2python
的文本,然后是urlextracter.gen_urls
来获取URL,在将http
添加到它们之后,我们使用check_links.check_link
检查链接并打印有用的消息。
问题:当我们从程序中请求该链接与实际单击网站时,有些链接显示出不同的结果
这是因为某些网站不喜欢机器人,但是由于Python请求将默认用户代理作为python-requests/2.25
,因此该网站会看到并禁止该程序获得结果。我们需要做的解决方法是使用另一个用户代理,我在Web浏览器Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
上复制了用户代理,然后我使用了response = requests.get(url, headers=HEADERS, stream=True)
,现在网站正确响应。
步骤5不同步
现在等待程序完成所有事情都很好,但是也太慢了。最慢的部分是等待网站获取。因为我们必须等待每个网站为我们提供结果。如果我们使用并发,这将更快,这意味着同时做事。
将其视为,Burger Shop A在5分钟内为您提供汉堡,Boba Shop B在3分钟内为您提供了Boba。您可以在8分钟内获得汉堡,然后再获得Boba。如果您同时订购两者,然后在准备就绪时收集它们,则只需要5分钟。
并发代码更为复杂,所以我不会在这里解释,您可以就此主题访问RealPython,他们在此主题上有一个很棒的教程。
步骤6扭曲
最后,我添加了一个代码来显示文件对话,以进一步简化用户。
import tkinter as tk
from tkinter import filedialog
file_path = filedialog.askopenfilename()
结论
这就是我的做法,希望您从中学到一些东西。