文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,,版权归原作者所有,如有问题请及时联系我们以作处理
作者:州的先生
原文链接: https://zmister.com/archives/1607.html
将 HTML 网页转换为 PDF 是很多人常见的一个需求,在浏览器上,我们可以通过浏览器的“打印”功能直接将网页打印输出为 PDF。
但是如果有多个网页就不好办了。
文章目录
网络上存在很多将 HTML 转换为 PDF 的软件和工具。比较著名的有 Carelib、wkhtmltopdf。
wkhtmltopdf 真是一个优秀的 HTML 转换 PDF 工具。其借助 Qt 的 WebKit 渲染引擎,将 HTML 文档渲染导出为 PDF 文档或图像。
功能十分完善,但是由于使用的渲染引擎是 Qt 的 WebKit,其没法对 ES6 的 JavaScript 代码提供支持,导致一些采用 ES6 编写的 HTML 页面渲染不出实际的效果来,导致州的先生最终放弃了它。
Carelib 是一个电子书管理软件,其中提供了各类文档的转换工具,所以可以借助其电子书转换工具来实现 HTMl 到 PDF 的转换。
这些都是用于桌面环境的二进制软件,如果要在 Python 中使用,要么使用 Popen() 方法调用这些二进制软件的命令,要么使用一些第三方的封装模块,比如: pdfkit 、 pypandoc 等,这些第三方模块通过集成调用上述二进制软件,封装了一些方便 Python 调用的接口。
上面介绍的那些 Python 第三方模块虽然可以很好的进行 HTML 到 PDF 的转换工作,但是都需要额外在计算机上安装其他的二进制软件,很多小伙伴并不喜欢这种调用方式。
不依赖于二进制软件的实现,有如下的方案:
这是一个基于 ReportLab、html5lib、PyPDF2 等 Python 模块构建的 HTML 到 PDF 转换模块。能够很好的支持 HTML5 、CSS2.1 和部分 CSS3 语法。
因为是基于 Report Lab 模块进行的开发,其对中文的支持在某些环境下会有问题。而且由于开发人员的变更,模块的功能出现了一些断层。但是仍然是一个非常棒的 HTML 转 PDF 模块。
这是一个用于 HTML 和 CSS 的可视化渲染引擎,可以将 HTML 文档导出为打印标准的 PDF 文件。
xhtml2pdf 模块也曾推荐使用这个模块来进行 HTML 转换 PDF 的工作。
这个模块功能很强大、效果很出色,但是,模块的依赖项太多了:
州的先生至今没有在 Windows 电脑上安装成功过!
在上述两种方案中,二进制程序的可控制性稍有不足,而纯 Python 实现的渲染解析则在功能上和依赖上不是有友好。
处理上述两种方案,我们还能采用第三种方式进行 HTMl 到 PDF 的转换。那就是借助 Web 自动化测试的浏览器内核和 Qt for Python 的 Web 引擎 来实现。
使用 Python 的小伙伴经常会使用 Selenium、pyppeteer 这两个 Web 自动化测试的模块来进行数据采集和 Web 自动化测试工作。
这两个模块都是用来驱动一个真实的浏览器来进行网页的操作。正是基于此,我们可以调用浏览器中打印相关的 API 接口,来实现 HTML 转 PDF 的功能。
例如,在 pyppeteer 中可以按照下面示例的方式,打开一个 HTML 文档,然后将其转换为 PDF 文档:
在 Qt5 中,Qt 使用新的 Chromium 内核代替了老旧的 WebKit 作为 Web 的渲染引擎。使得在 Qt 中进行可以现代化的浏览器开发。
借助于 Qt 的 Python 实现(PyQt5 系列 和 PySide2 系列),我们可以直接调用 Qt 中的 Web 引擎相关的接口。
其中 QtWebEngineWidgets 子模块中的 QWebEngineView() 类提供了 printToPdf 方法供我们将网页打印为 PDF 文档,所以基于此,我们也可以使用 PyQt5 或 PySide2 进行 HTML 转换 PDF,示例如下所示:
markdown中写下你的文章,并使用Python将它们转换成HTML-作者Florian Dahlitz,于2020年5月18日(15分钟)
介绍
几个月前,我想开通自己的博客,而不是使用像Medium这样的网站。这是一个非常基础的博客,所有的文章都是HTML形式的。然而,有一天,我突然产生了自己编写Markdown到HTML生成器的想法,最终这将允许我用markdown来编写文章。此外,为它添加诸如估计阅读时间之类的扩展特性会更容易。长话短说,我实现了自己的markdown到HTML生成器,我真的很喜欢它!
在本系列文章中,我想向您展示如何构建自己的markdown到HTML生成器。该系列由三部分组成:
第一部分(本文)介绍了整个管线的实现。
第二部分通过一个模块扩展了实现的管线,该模块用于计算给定文章的预计阅读时间。
第三部分演示如何使用管线生成自己的RSS摘要。
这三部分中使用的代码都可以在GitHub上找到。
备注:我的文章中markdown到HTML生成器的想法基于Anthony Shaw文章中的实现。
项目构建
为了遵循本文的内容,您需要安装几个软件包。我们把它们放进requirements.txt文件。
Markdown是一个包,它允许您将markdown代码转换为HTML。之后我们用Flask产生静态文件。
但在安装之前,请创建一个虚拟环境,以避免Python安装出现问题:
激活后,您可以使用pip安装requirements.txt中的依赖。
很好!让我们创建几个目录来更好地组织代码。首先,我们创建一个app目录。此目录包含我们提供博客服务的Flask应用程序。所有后续目录都将在app目录内创建。其次,我们创建一个名为posts的目录。此目录包含要转换为HTML文件的markdown文件。接下来,我们创建一个templates目录,其中包含稍后使用Flask展示的模板。在templates目录中,我们再创建两个目录:
posts包含生成的HTML文件,这些文件与应用程序根目录中posts目录中的文件相对应。
shared包含在多个文件中使用的HTML文件。
此外,我们还创建了一个名为services的目录。该目录将包含我们在Flask应用程序中使用的模块,或者为它生成某些东西。最后,创建一个名为static的目录带有两个子目录images和css。自定义CSS文件和文章的缩略图将存储在此处。
您的最终项目结构应如下所示:
令人惊叹!我们完成了一般的项目设置。我们来看看Flask的设置。
Flask设置
路由
我们在上一节安装了Flask。但是,我们仍然需要一个Python文件来定义用户可以访问的端点。在app目录中创建main.py并将以下内容复制到其中。
该文件定义了一个具有两个端点的基础版Flask应用程序。用户可以使用/route访问第一个端点返回索引页,其中列出了所有文章。
第二个端点是更通用的端点。它接受post的名称并返回相应的HTML文件。
接下来,我们通过向app目录中添加一个__init__.py,将其转换为一个Python包。此文件为空。如果您使用UNIX计算机,则可以从项目的根目录运行以下命令:
模板
现在,我们创建两个模板文件index.html以及layout.html,都存储在templates/shared目录中。这个layout.html模板将用于单个博客条目,而index.html模板用于生成索引页,从中我们可以访问每个帖子。让我们从index.html模板开始。
它是一个基本的HTML文件,其中有两个元标记、一个标题和两个样式表。注意,我们使用一个远程样式表和一个本地样式表。远程样式表用于启用Bootstrap[1]类。第二个是自定义样式。我们晚点再定义它们。
HTML文件的主体包含一个容器,其中包含Jinja2[2]逻辑,用于为每个post生成Bootstrap卡片[3]。您是否注意到我们不直接基于变量名访问这些值,而是需要将[0]添加到其中?这是因为文章中解析的元数据是列表。实际上,每个元数据元素都是由单一元素组成的列表。我们稍后再看。到目前为止,还不错。让我们看看layout.html模板。
如你所见,它比前一个短一点,简单一点。文件头与index.html文件很相似,除了我们有不同的标题。当然,我们可以共用一个模板,但是我不想让事情变得更复杂。
body中的容器仅定义一个h1标记。然后,我们提供给模板的内容被插入并呈现。
样式
正如上一节所承诺的,我们将查看自定义CSS文件style.css. 我们在static/css中找到该文件,并根据需要自定义页面。下面是我们将用于基础示例的内容:
我不喜欢Bootstrap中blockquotes的默认外观,所以我们在左侧添加了一点间距和边框。此外,blockquote段落底部的页边空白将被删除。不删除的话看起来很不自然。
最后但并非最不重要的是,左右两边的填充被删除。由于两边都有额外的填充,缩略图没有正确对齐,所以在这里删除它们。
到现在为止,一直都还不错。我们完成了关于Flask的所有工作。让我们开始写一些帖子吧!
写文章
正如标题所承诺的,你可以用markdown写文章-是的!在写文章的时候,除了保证正确的markdown格式外,没有其他需要注意的事情。
在完成本文之后,我们需要在文章中添加一些元数据。此元数据添加在文章之前,并由三个破折号分隔开来---。下面是一个示例文章(post1.md)的摘录:
注意:您可以在GitHub库的app/posts/post1.md中找到完整的示例文章。
在我们的例子中,元数据由标题、副标题、类别、发布日期和index.html中卡片对应缩略图的路径组成.
我们在HTML文件中使用了元数据,你还记得吗?元数据规范必须是有效的YAML。示例形式是键后面跟着一个冒号和值。最后,冒号后面的值是列表中的第一个也是唯一的元素。这就是我们通过模板中的索引运算符访问这些值的原因。
假设我们写完了文章。在我们可以开始转换之前,还有一件事要做:我们需要为我们的帖子生成缩略图!为了让事情更简单,只需从你的电脑或网络上随机选取一张图片,命名它为placeholder.jpg并把它放到static/images目录中。GitHub存储库中两篇文章的元数据包含一个代表图像的键值对,值是placeholder.jpg。
注意:在GitHub存储库中,您可以找到我提到的两篇示例文章。
markdown到HTML转换器
最后,我们可以开始实现markdown to HTML转换器。因此,我们使用我们在开始时安装的第三方包Markdown。我们先创建一个新模块,转换服务将在其中运行。因此,我们在service目录中创建了converter.py。我们一步一步看完整个脚本。您可以在GitHub存储库中一次查看整个脚本。
首先,我们导入所需的所有内容并创建几个常量:
ROOT指向我们项目的根。因此,它是包含app的目录。
POSTS_DIR是以markdown编写的文章的路径。
TEMPLATE_DIR分别指向对应的templates目录。
BLOG_TEMPLATE_文件存储layout.html的路径。
INDEX_TEMPLATE_FILE是index.html
BASE_URL是我们项目的默认地址,例如。https://florian-dahlitz.de.默认值(如果不是通过环境变量DOMAIN提供的话)是http://0.0.0.0:5000。
接下来,我们创建一个名为generate_entries的新函数。这是我们定义的唯一一个转换文章的函数。
在函数中,我们首先获取POSTS_DIR目录中所有markdown文件的路径。pathlib的awesome glob函数帮助我们实现它。
此外,我们定义了Markdown包需要使用的扩展。默认情况下,本文中使用的所有扩展都随它的安装一起提供。
注意:您可以在文档[4]中找到有关扩展的更多信息。
此外,我们实例化了一个新的文件加载程序,并创建了一个在转换项目时使用的环境。随后,将创建一个名为all_posts的空列表。此列表将包含我们处理后的所有帖子。现在,我们进入for循环并遍历POSTS_DIR中找到的所有文章。
我们启动for循环,并打印当前正在处理的post的路径。如果有什么东西出问题了,这尤其有用。然后我们就知道,哪个文章的转换失败了。
接下来,我们在默认url之后增加一部分。假设我们有一篇标题为“面向初学者的Python”的文章。我们将文章存储在一个名为python-for-beginners.md,的文件中,因此生成的url将是http://0.0.0.0:5000/posts/python-for-beginners。
变量url_html存储的字符串与url相同,只是我们在末尾添加了.html。我们使用此变量定义另一个称为target_file.的变量。变量指向存储相应HTML文件的位置。
最后,我们定义了一个变量md,它表示markdown.Markdown的实例,用于将markdown代码转换为HTML。您可能会问自己,为什么我们没有在for循环之前实例化这个实例,而是在内部实例化。当然,对于我们这里的小例子来说,这没有什么区别(只是执行时间稍微短一点)。但是,如果使用诸如脚注之类的扩展来使用脚注,则需要为每个帖子实例化一个新实例,因为脚注添加后就不会从此实例中删除。因此,如果您的第一篇文章使用了一些脚注,那么即使您没有明确定义它们,所有其他文章也将具有相同的脚注。
让我们转到for循环中的第一个with代码块。
实际上,with代码块打开当前post并将其内容读入变量content。之后调用_md.convert将以markdown方式写入的内容转换为HTML。随后,env环境根据提供的模板BLOG_TEMPLATE_FILE(即layout.html如果你还记得的话)渲染生成的HTML。
第二个with 代码块用于将第一个with 代码块中创建的文档写入目标文件。
以下三行代码从元数据中获取发布日期(被发布的日期),将其转换为正确的格式(RFC 2822),并将其分配回文章的元数据。此外,生成的post_dict被添加到all_posts列表中。
我们现在出了for循环,因此,我们遍历了posts目录中找到的所有posts并对其进行了处理。让我们看看generate_entries函数中剩下的三行代码。
我们按日期倒序对文章进行排序,所以首先显示最新的文章。随后,我们将文章写到模板目录一个新创建的index.html文件中。别把index.html错认为templates/shared目录中的那个。templates/shared目录中的是模板,这个是我们要使用Flask服务的生成的。
最后我们在函数generate_entries之后添加以下if语句。
这意味着如果我们通过命令行执行文件,它将调用generate_entries函数。
太棒了,我们完成了converter.py脚本!让我们从项目的根目录运行以下命令来尝试:
您应该看到一些正在转换的文件的路径。假设您编写了两篇文章或使用了GitHub存储库中的两篇文章,那么您应该在templates目录中找到三个新创建的文件。首先是index.html,它直接位于templates目录中,其次是templates/posts目录中的两个HTML文件,它们对应于markdown文件。
最后启动Flask应用程序并转到http://0.0.0.0:5000。
总结
太棒了,你完成了这个系列的第一部分!在本文中,您已经学习了如何利用Markdown包创建自己的Markdown to HTML生成器。您实现了整个管线,它是高度可扩展的,您将在接下来的文章中看到这一点。
希望你喜欢这篇文章。一定要和你的朋友和同事分享。如果你还没有,考虑在Twitter上关注我@DahlitzF或者订阅我的通知,这样你就不会错过任何即将发表的文章。保持好奇心,不断编码!
参考文献
Bootstrap (http://getbootstrap.com/)
Primer on Jinja Templating (https://realpython.com/primer-on-jinja-templating/)
Bootstrap Card (https://getbootstrap.com/docs/4.4/components/card/)
Python-Markdown Extensions (https://python-markdown.github.io/extensions/)
Tweet
英文原文:https://florian-dahlitz.de/blog/build-a-markdown-to-html-conversion-pipeline-using-python
译者:阿布铥
爬虫正则表达式参考我上一篇文章:Python 爬虫正则表达式和re库
在爬虫过程中,可以利用正则表达式去提取信息,但是有些人觉得比较麻烦。因为花大量时间分析正则表达式。这时候可以用高效的网页解析库Beautiful Soup。
Beautiful Soup 是一个HTML/XML 的解析器,主要用于解析和提取 HTML/XML 数据。
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更加强大,速度更快,推荐安装。
下面是各种解析器优缺点
Beautiful Soup 3 目前已经停止开发,推荐在现在的项目中使用Beautiful Soup 4,不过它已经被移植到BS4了,也就是说导入时我们需要 import bs4。
安装Beautiful Soup
pip install beautifulsoup4
根据操作系统不同,可以选择下列方法来安装lxml,安装解析器:
apt-get install Python-lxml
easy_install lxml
pip install lxml
创建对象时,指定解析器,这里为lxml
from bs4 import BeautifulSoup
bs = BeautifulSoup(html,"lxml")
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment .
(1)Tag
标签,最基本的信息组织单元,分别用<>和标明开头和结尾,通俗点讲就是 HTML 中的一个个标签。
Tag有很多方法和属性,tag中最重要的属性: name和attributes。
name:
每个tag都有自己的名字,通过 .name 来获取:
惯例,同样以豆瓣电影排行做分析,链接为:https://movie.douban.com/top250
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/65.0.3325.162 Safari/537.36'}
url='https://movie.douban.com/top250'
req=requests.get(url,headers=headers)
html=req.text
#print(req.text)
soup=BeautifulSoup(html,'lxml')
print(soup.h1)
print(soup.a)
执行结果:
<h1>豆瓣电影 Top 250</h1>
<a class="nav-login" href="https://accounts.douban.com/passport/login?source=movie" rel="nofollow">登录/注册</a>
以上,就直接提取到标签h1和a 的内容了,之所以只有一个,因为只提取第一个匹配到的内容。
Attributes:
属性,一个tag可能有很多个属性, . tag的属性的操作方法与字典相同。
如上:ol class="grid_view" 的属性, 标签名为ol,属性为class,属性值为:grid_view
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/65.0.3325.162 Safari/537.36'}
url='https://movie.douban.com/top250'
req=requests.get(url,headers=headers)
html=req.text
#print(req.text)
soup=BeautifulSoup(html,'lxml')
#获取标签div所有属性,得到的是一个字典
print(soup.div.attrs)
#获取标签ol属性为class的值
print(soup.ol['class'])
执行结果:
{'id': 'db-global-nav', 'class': ['global-nav']}
['grid_view']
因为是字典属性,所以tag的属性可以被添加,删除或修改。不过,对于修改删除的操作,不是我们的主要用途,有需要的自行参考官方文档。
(2)NavigableString
直译为:可以遍历的字符串,通过名称可知,得到字符串。
标签内非属性字符串,格式:soup.\<tag>.string, NavigableString可以跨越多个层次。
如,得到了标签的内容,要想获取标签内部的文字,用 .string 即可。
上面代码改为:
print(soup.h1.string)
执行结果:
豆瓣电影 Top 250
(3)BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称。
print(soup.name)
执行结果:
[document]
(4)Comment
注释及特殊字符串,Tag , NavigableString , BeautifulSoup 几乎覆盖了html和xml中的所有内容,但是还有一些特殊对象.容易让人担心的内容是文档的注释部分:
from bs4 import BeautifulSoup
markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string
print(type(comment))
print(comment)
执行结果:
<class 'bs4.element.Comment'>
Hey, buddy. Want to buy a used parser?
HTML基本格式:<>…</>构成了所属关系,遍历形成了标签的树形结构。
所以有时候不能做到一步就得到想要的元素,需要先选中一个元素再以它为基准再选择它的子节点,父节点,兄弟节点等。
(1)子节点和子孙节点
子节点属性:.contents .children
.content
tag 的 .content 属性可以将tag的子节点以列表的方式输出
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/65.0.3325.162 Safari/537.36'}
url='https://movie.douban.com/top250'
req=requests.get(url,headers=headers)
html=req.text
#print(req.text)
soup=BeautifulSoup(html,'lxml')
print(soup.ol.contents)
执行结果:
['\n', <li>
<div class="item">
<div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">
<img alt="肖申克的救赎" class="" src="https://img9.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
</a>
</div>
<div class="info">
...
输出方式为列表,所以可以用列表索引来获取它的某一个元素。
print(soup.ol.contents[1])
.children
返回的不是一个 list,不过我们可以通过遍历获取所有子节点。
print(soup.ol.children)
执行结果:
<list_iterator object at 0x7fbf14fbc4c0>
打印输出 .children ,可以发现它是一个 list 生成器对象,所以需要遍历一下获取内容。
for child in soup.ol.children:
print(child)
输入内容和.content差不多。
子孙节点.descendants
如果要获得所有的子孙节点的话,可以调用descendants属性,返回结果还是生成器,所以需要遍历一下输出可以看见span节点
print(soup.ol.descendants)
#print(soup.ol.children)
for child in soup.ol.descendants:
print(child)
descendants会递归查询所有子节点,得到所有的子孙节点。
(2)父节点和祖父节点
获取父节点.parent
print(soup.ol.parent)
获取所有祖先节点,同理需要遍历获取。
for parent in soup.ol.parents:
print(parent)
(3)兄弟节点
获取兄弟节点:.next_sibling 和 .previous_sibling
next_sibling和previous_sibling分别获取节点的下一个和上一个兄弟元素。
print(soup.li.next_sibling)
print(soup.li.previous_sibling)
如果节点不存在,则返回 None,实际中通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行。
全部兄弟节点:next_siblings 和 previous_siblings
分别返回后面和前面的兄弟节点,同理,所有节点需要遍历获得。
print(soup.li.next_siblings)
print(soup.li.previous_siblings)
for sibling in soup.li.next_siblings:
print(sibling)
for previous in soup.li.previous_siblings:
print(previous)
(4)回退和前进节点
前后节点:.next_element 和 .previous_element
与 .next_sibling .previous_sibling 不同,它并不是针对于兄弟节点,而是在所有节点,不分层次
比如 head 节点为
<head><title>The Dormouse's story</title></head>
那么它的下一个节点便是 title,它是不分层次关系的。
所有前后节点:.next_elements 和 .previous_elements
同理,返回的是迭代器,需要遍历获得。
eautiful Soup定义了很多搜索方法,主要用的2个方法:find() 和 find_all()
(1)find_all
语法:find_all(name, attrs, recursive, text, **kwargs)
name:
我们可以根据节点名来查询元素。name可以是:字符串、正则表达式、列表、True、方法
print(soup.find_all('a'))
因为是Tag类型,我们可以进行嵌套查询.
for a in soup.find_all('a'):
print(a.find_all('span'))
print(a.string)
attrs
除了根据节点名查询的话,同样的也可以通过属性来查询。
print(soup.find_all(attrs={'id': 'link1'}))
print(soup.find_all(attrs={'name': 'Dormouse'}))
常用的属性比如class,我们可以直接传入class这个参数。在这里需要注意的是class是Python的保留字,所以在class的后面加上下划线。
print(soup.find_all(class_="title"))
执行结果:
<span class="title">肖申克的救赎</span>, <span class="title"> / The Shawshank Redemption</span>, <span class="title">霸王别姬</span>, <span class="title">阿甘正传</span>
(2)find
除了find_all( )方法,还有find( )方法,前者返回的是多个元素,以列表形式返回,后缀是返回一个元素。即第一个元素。
find( )与find_all( )的使用方法相同。
find_parents() 和find_parent():前者返回所有祖先节点,后者返回直接父节点。
find_next_siblings()和find_next_sibling():前者返回后面的所有兄弟节点,后者返回后面第一个兄弟节点。
find_previous_siblings和find_previous_sibling():前者返回前面的所有兄弟节点,后者返回前面第一个兄弟节点。
Beautiful Soup还提供了另一种选择器,即CSS选择器。
soup.select(),返回类型是 list。
同样可以用 标签名、类名、 id 名、组合、属性查找。
(1)soup.select()
获取title标签节点
print(soup.select('title'))
获取class为title的节点
print(soup.select('.title'))
获取li标签下的a节点
print(soup.select('li a'))
查找时还可以加入属性元素,属性需要用中括号括起来,
注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到
print soup.select('a[href="http://example.com/elsie"]')
(2)嵌套选择
同样可以使用嵌套查询
for ul in soup.select('ul'):
print(ul.select('li'))
(3)获取属性
for ul in soup.select('ul'):
print(ul['id'])
print(ul.attrs['id'])
(4)获取文本
for li in soup.select('li'):
print('String:', li.string)
print('get text:', li.get_text())
通过以上的方法,现在获取豆瓣电影排行首页的排名、电影名、导演演员、年份类型。
从页面分析,所有影片信息,在class标签值为grid_view的里面。
所以第一步获取所有grid_view里面所有li标签的值,返回的是一个列表。
list= soup.find(class_='grid_view').find_all('li')
排序,在列表每个元素中,获取em标签值,为排序,只取字符串。
find('em').string
电影名称,获取第一个title值
find(class_='title').string
导演和年代信息,在标签p当中,获取的是text文本格式。由于中间有空格,还有br换行符,所以最后还需要replace替换掉。
item.find('p').text.replace(' ','')
最终代码为:
url='https://movie.douban.com/top250'
req=requests.get(url,headers=headers)
html=req.text
#print(req.text)
soup=BeautifulSoup(html,'lxml')
list= soup.find(class_='grid_view').find_all('li')
for item in list:
item_num=item.find('em').string
item_name=item.find(class_='title').string
item_act=item.find('p').text.replace(' ','')
print("排名:"+item_num,"\n电影名称:"+item_name,item_act)
执行结果:
排名:1
电影名称:肖申克的救赎
导演:弗兰克·德拉邦特FrankDarabont 主演:蒂姆·罗宾斯TimRobbins/...
1994 / 美国 / 犯罪剧情
排名:2
电影名称:霸王别姬
导演:陈凯歌KaigeChen 主演:张国荣LeslieCheung/张丰毅FengyiZha...
1993 / 中国大陆中国香港 / 剧情爱情同性
排名:3
电影名称:阿甘正传
导演:罗伯特·泽米吉斯RobertZemeckis 主演:汤姆·汉克斯TomHanks/...
1994 / 美国 / 剧情爱情
排名:4
电影名称:泰坦尼克号
导演:詹姆斯·卡梅隆JamesCameron 主演:莱昂纳多·迪卡普里奥Leonardo...
1997 / 美国墨西哥澳大利亚加拿大 / 剧情爱情灾难
排名:5
电影名称:这个杀手不太冷
导演:吕克·贝松LucBesson 主演:让·雷诺JeanReno/娜塔莉·波特曼...
1994 / 法国美国 / 剧情动作犯罪
排名:6
电影名称:美丽人生
导演:罗伯托·贝尼尼RobertoBenigni 主演:罗伯托·贝尼尼RobertoBeni...
1997 / 意大利 / 剧情喜剧爱情战争
排名:7
电影名称:千与千寻
导演:宫崎骏HayaoMiyazaki 主演:柊瑠美RumiHîragi/入野自由Miy...
2001 / 日本 / 剧情动画奇幻
排名:8
电影名称:辛德勒的名单
导演:史蒂文·斯皮尔伯格StevenSpielberg 主演:连姆·尼森LiamNeeson...
1993 / 美国 / 剧情历史战争
排名:9
电影名称:盗梦空间
导演:克里斯托弗·诺兰ChristopherNolan 主演:莱昂纳多·迪卡普里奥Le...
2010 / 美国英国 / 剧情科幻悬疑冒险
排名:10
电影名称:星际穿越
导演:克里斯托弗·诺兰ChristopherNolan 主演:马修·麦康纳MatthewMc...
2014 / 美国英国加拿大 / 剧情科幻冒险
排名:11
电影名称:忠犬八公的故事
导演:莱塞·霍尔斯道姆LasseHallström 主演:理查·基尔RichardGer...
2009 / 美国英国 / 剧情
排名:12
电影名称:楚门的世界
导演:彼得·威尔PeterWeir 主演:金·凯瑞JimCarrey/劳拉·琳妮Lau...
1998 / 美国 / 剧情科幻
排名:13
电影名称:海上钢琴师
导演:朱塞佩·托纳多雷GiuseppeTornatore 主演:蒂姆·罗斯TimRoth/...
1998 / 意大利 / 剧情音乐
排名:14
电影名称:三傻大闹宝莱坞
导演:拉库马·希拉尼RajkumarHirani 主演:阿米尔·汗AamirKhan/卡...
2009 / 印度 / 剧情喜剧爱情歌舞
排名:15
电影名称:机器人总动员
导演:安德鲁·斯坦顿AndrewStanton 主演:本·贝尔特BenBurtt/艾丽...
2008 / 美国 / 科幻动画冒险
排名:16
电影名称:放牛班的春天
导演:克里斯托夫·巴拉蒂ChristopheBarratier 主演:让-巴蒂斯特·莫尼...
2004 / 法国瑞士德国 / 剧情喜剧音乐
排名:17
电影名称:无间道
导演:刘伟强/麦兆辉 主演:刘德华/梁朝伟/黄秋生
2002 / 中国香港 / 剧情犯罪惊悚
排名:18
电影名称:疯狂动物城
导演:拜伦·霍华德ByronHoward/瑞奇·摩尔RichMoore 主演:金妮弗·...
2016 / 美国 / 喜剧动画冒险
排名:19
电影名称:大话西游之大圣娶亲
导演:刘镇伟JeffreyLau 主演:周星驰StephenChow/吴孟达ManTatNg...
1995 / 中国香港中国大陆 / 喜剧爱情奇幻古装
排名:20
电影名称:熔炉
导演:黄东赫Dong-hyukHwang 主演:孔侑YooGong/郑有美Yu-miJung/...
2011 / 韩国 / 剧情
排名:21
电影名称:控方证人
导演:比利·怀尔德BillyWilder 主演:泰隆·鲍华TyronePower/玛琳·...
1957 / 美国 / 剧情犯罪悬疑
排名:22
电影名称:教父
导演:弗朗西斯·福特·科波拉FrancisFordCoppola 主演:马龙·白兰度M...
1972 / 美国 / 剧情犯罪
排名:23
电影名称:当幸福来敲门
导演:加布里尔·穆奇诺GabrieleMuccino 主演:威尔·史密斯WillSmith...
2006 / 美国 / 剧情传记家庭
排名:24
电影名称:触不可及
导演:奥利维·那卡什OlivierNakache/艾力克·托兰达EricToledano 主...
2011 / 法国 / 剧情喜剧
排名:25
电影名称:怦然心动
导演:罗伯·莱纳RobReiner 主演:玛德琳·卡罗尔MadelineCarroll/卡...
2010 / 美国 / 剧情喜剧爱情
推荐使用lxml解析库,必要时选择html.parser。相对于正则表达式,Beautiful Soup更加简单,但是网上有些推荐正则表达式,理由是精确。
具体用哪个,还是根据环境选择吧,一起使用都可以。
*请认真填写需求信息,我们会在24小时内与您取得联系。