上一篇内容:Python爬虫初级(六)—— 正则表达式库入门
我们首先查看待爬取页面:http://www.dxy.cn/bbs/thread/626626#626626,具体形式为下图:
我们查看源代码信息:
可以发现留言板块的内容在页面源代码全部直接显示了出来,那么我们可以尝试直接进行爬取,我们采取的思路首先是 requests 库 + bs4 库,这两者的具体用法在前面的文章均已涉及。
首先我们可以在IDLE上检查爬取链接是否正常,直接展示代码:
>>> import requests
>>> import re
>>> from bs4 import BeautifulSoup
>>> url = "http://www.dxy.cn/bbs/thread/626626#626626"
>>> headers = {"user-agent":"Mozilla/5.0"}
>>> res = requests.get(url, headers=headers, stream=True)
>>> res.status_code
200
>>> text = res.text
>>> soup = BeautifulSoup(text)
>>> text[1000:1300]
'og:description" content="我遇到一个“怪”病人,向大家请教。她,42岁。反复惊吓后晕厥30余年。每次受响声惊吓后发生跌倒,短暂意识丧失。无逆行性遗忘,无抽搐,无口吐白沫,无大小便失禁。多次跌倒致外伤。婴儿时有惊厥史。入院查体无殊。ECG、24小时动态心电图无殊;头颅MRI示小软化灶;脑电图无殊。入院后有数次类似发作。请问该患者该做何诊断,还需做什么检查,治疗方案怎样?"/>\n \n
我们想要抓取链接,先在上面的源代码中对标题层级结构进行分析:
然后直接写出相关代码:
>>> title = soup("div", id="postview")[0].tr.th.h1.contents[0]
['\n 晕厥待查——请教各位同仁 ']
>>> title = title.replace(" ", "")
>>> title = title.replace("\n", "")
>>>> title
'晕厥待查——请教各位同仁'
下面同理可以查看其他信息,下面我们为了便于操作直接采用 CSS 类名查找:
>>> context = soup.select("[class~=postbody]")
# 返回所有内容信息
>>> cont = context[1].contents[0]
>>> cont = cont.replace(" ", "")
>>> cont = cont.replace("\n", "")
>>> cont
'从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。'
测试代码写完后,我们写出完整代码:
import requests
from bs4 import BeautifulSoup
def getHTML(url):
try:
headers = {"user-agent":"Mozilla/5.0"}
res = requests.get(url, headers=headers, stream=True)
res.raise_for_status
res.encoding = res.apparent_encoding
return res.text
except:
return ""
def ParseFromPage(html):
commentList = []
soup = BeautifulSoup(html)
title = soup("div", id="postview")[0].tr.th.h1.contents[0]
title = title.replace(" ", "")
title = title.replace("\n", "")
context = soup.select("[class~=postbody]")
for i in range(len(context)):
cont = context[i].contents[0]
cont = cont.replace(" ", "")
commentList.append(cont)
return title, commentList
def main():
base_url = "http://www.dxy.cn/bbs/thread/626626#626626"
html = getHTML(base_url)
title, cList = ParseFromPage(html)
print(title, cList)
main()
我们爬取完单一页面后,我们可以考虑,是否可以爬取更多的页面。我们的思考出发点是丁香园每个页面的链接下面都会存在一个引向其他同类型页面的链接,比如:
我们可以看到,下面的 “骨折手术后一周突发心跳骤停,抢救无效死亡,什么原因?”这段话不就是我们要找的链接,点开后也确实如我们所料,页面结构的解析和本页面的解析一样,我们完全可以复用这段代码,只需要改变一下 url 即可。下面我们尝试通过 re 库获取此 url 链接:
>>> import re
>>> href = re.findall(r' , text)
>>> href
['http://job.dxy.cn/bbs/topic/43200651', 'http://www.dxy.cn/bbs/topic/43177945', 'http://Radiology.dxy.cn/bbs/topic/43179123', 'http://www.dxy.cn/bbs/topic/43172871']
这里我们看到有四个链接,但并不是每个链接都是我们需要的,通过观察后我们发现,只有以 “http://www.dxy.cn/bbs/topic” 开头的链接才是我们需要的,我们可以将查找链接的方式改为:
>>> re.findall(r',text)
['http://www.dxy.cn/bbs/topic/43177945"', 'http://www.dxy.cn/bbs/topic/43172871"']
我们看到返回了两个正确结果,为了不增大网站压力,我们修改主函数,仅仅爬取十条链接的内容,并存储到 dxy.txt 文件中,主函数代码如下:
def main():
base_url = "http://www.dxy.cn/bbs/thread/626626#626626"
for i in range(10):
html = getHTML(base_url)
title, cList = ParseFromPage(html)
with open("dxy.txt", "a", encoding="utf-8") as f:
f.write(title)
f.write("\n")
for i in range(len(cList)):
f.write(cList[i])
f.write("\n")
f.write("\n")
try:
url_list = re.findall(r',html)
base_url = url_list[0]
except:
continue
此代码应能正确爬取链接,代码规范有待网友指正。
我们还可以使用 lxml 爬取内容,事实上此代码会更加简洁, lxml 的具体用法将在下期内容展开,以下直接简单使用之:
from lxml import html, etree
>>> tree1 = html.tostring(tree.xpath('//td[@class="postbody"]')[1])
>>> txt = HTMLParser().unescape(tree1.decode('utf-8'))
>>> txt.replace(" ","")
'\n\n从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。
贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”
作者:林文华任自文丁燕生
http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm\n\t\n' '
其他信息的抽取以及代码的结构化同上即可。
下一篇内容:Python爬虫初级(八)—— lxml 详解及代理IP爬取