程序员是这样学习【中药学】知识的,先用python采集分析一波

举报
梦想橡皮擦 发表于 2022/01/24 08:30:12 2022/01/24
【摘要】 本次博客为《爬虫 120 例》第 33 例,重点学习的模块为 pyquery。 目标站点分析本次要采集的站点为:http://www.zhongyoo.com/name/page_1.html,其中列表页规则如下:http://www.zhongyoo.com/name/page_1.htmlhttp://www.zhongyoo.com/name/page_2.htmlhttp://www...

本次博客为《爬虫 120 例》第 33 例,重点学习的模块为 pyquery

目标站点分析

本次要采集的站点为:http://www.zhongyoo.com/name/page_1.html,其中列表页规则如下:

http://www.zhongyoo.com/name/page_1.html
http://www.zhongyoo.com/name/page_2.html
http://www.zhongyoo.com/name/page_{页码}.html

每页有 20 条数据,可查阅总页码为 45 页。

详情页地址可通过标题指向的链接获取。

最终的目标数据是获取详情页,各个指标数据,具体如下图所示(不同页面规则有细微差异,解析数据时需要特别注意)

本爬虫编写分为两个步骤完成,第一步将所有详情页保存到本地,第二步提取本地 HTML 数据。

编码时间

保存 HTML 静态数据到本地,重点注意编码问题即可。

from pyquery import PyQuery as pq
import time
import requests
import chardet


def get_html(page):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    }
    res = requests.get(url='http://www.zhongyoo.com/name/page_{}.html'.format(page), headers=headers, timeout=5)

    res.encoding = "gb2312"

    pq_data = pq(res.text)
    titles = pq_data.find("strong>a.title")

    for item in titles:
        # 下面两种写法都能获取到 href 属性
        # print(pq(item).attr('href'))
        # print(item.attrib['href'])
        link = pq(item).attr('href')
        print(link)
        save(link)
    # return len(res.text)


def save(link):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    }
    doc = pq(url=link, headers=headers, encoding='gbk')
    title = doc('title')
    print(title.text())
    if title:
        title = title.text().split('_')[0]

    text = doc.html()

    with open("./html/{}.html".format(title), "w+") as f:
        f.write(text.encode("gbk", "ignore").decode("gbk"))


if __name__ == '__main__':
    # 静态页面获取代码逻辑
    page_data = list(range(1, 46))
    ret = map(get_html, page_data)
    for item in ret:
        print(item)

在提取网页元素的 href 属性时碰到一个 BUG,如下所示:

AttributeError: 'HtmlElement' object has no attribute 'attr'

此时可以直接使用 ElementTree API 访问标签的属性,也可以对 HtmlElemente 进行封装,即使用 pq 进行包裹,代码如下:

pq(item).attr('href')

还有一种方式是调用上述变量 titles.items 方法,此时就可以通过 .attr 函数,获取 href 属性。

由于网页是 gb2312 编码,实测中发现是 gbk 编码,但在存储文件时,还是存在字符无法被转换,故增加如下代码,去除无法被转换的字符。

with open("./html/{}.html".format(title), "w+") as f:
	f.write(text.encode("gbk", "ignore").decode("gbk"))

注意以下问题,都是字符编码的问题。

> 'gb2312' codec can't encode character '\u85a2' in position 14654: illegal multibyte sequence
> 'gbk' codec can't encode character '\xa9' in position 20633: illegal multibyte sequence
> 'utf-8' codec can't decode byte 0xb2 in position 164: invalid start byte

编写数据提取部分代码时,发现使用 pyquery 提取会变得很复杂,还是需要正则表达式的介入,以下代码可供参考。

def extract_data():
    file_names = os.listdir("./html/")
    for file in file_names:
        with open(f"./html/{file}", "r") as f:
            html_content = f.read()
            # 解析数据
            pq_obj = pq(html_content)
            items = pq_obj.find('div.text p')
            print("获取到的段落数为,", len(items))
            # 等待提取的字符串
            item_str = ""
            for item in items:
                text = pq(item).text()
                item_str += text
            # 使用正则提取数据
            # 正名/中药名/药名
            name_p = re.compile('【(正名|中药名|药名)】([\s\S]*?)【')
            name = name_p.findall(item_str)
            # 别名
            alias_p = re.compile('【别名】([\s\S]*?)【')
            alias = alias_p.findall(item_str)
            # 英文名
            en_name_p = re.compile('【英文名】([\s\S]*?)【')
            en_name = en_name_p.findall(item_str)
            print(name, alias, en_name)

如果你看到这里,那么一个新的案例又实现啦。

收藏时间

代码仓库地址:https://codechina.csdn.net/hihell/python120,去给个关注或者 Star 吧。

今天是持续写作的第 220 / 365 天。
可以关注点赞评论收藏

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。