Python 爬虫学习之路 第一天

2022-10-20 12:08:12

算法太难,直接来学爬虫

第一个爬虫程序

爬取这个网站的所有电影名称,评分,类型,内容简介,封面(只是一个网址)和上映时间

Scrape | Movie

网站在上面

所谓爬虫,就是对于一个网站的爬取,我们先关注url,对于这个网站分为两个,列表页和详情页,因此需要函数去分别提取这两个页的url,所对应的html代码,并且去解析它,最后得到所要的结果。

因此第一个我们要做的就是对于页面的爬取,以下是代码

# 页面爬取方法
def scrape_page(url):
    logging.info('scraping %s...' , url)
    try:
        response = requests.get(url)
        if response.status_code == 200:
            return response.text
        logging.error('get invalid status code %s while scraping %s', response.status_code, url)
    # 异常处理
    except requests.RequestException:
        # exec_info 可以打印出错误信息
        logging.error('error occurred while scraping %s' , url , exec_info = True)

这个函数所实现的就是,对于一个网址,去爬取它的html代码,我们直接使用get请求即可,如果状态码是200,那么直接返回所对应网址的html代码,否则输出错误日志

然后需要的就是,对于一种网页进行爬取,先定义列表页

# 列表页的爬取方法
# page 接受page参数
def scrape_index(page):
    # https://ssr1.scrape.center/page/2
    index_url = f'{BASE_URL}/page/{page}'
    return scrape_page(index_url)

我们可以将固定格式的url列表页进行字符的拼接得到需要的url,最后再使用scrape_page方法,获取这个页面的html代码

再下来,就是对于每一个列表页解析,得到详情页的url

# 解析列表页
def parse_index(html):
    # <a data-v-7f856186 href="/detail/1" class="name">
    pattern = re.compile('<a.*?href="(.*?)".*?class="name">')
    items = re.findall(pattern, html) # 找到网页中的所有和pattern匹配的内容
    if not items:
        return []
    for item in items:
        detail_url = urljoin(BASE_URL, item) # 拼接得到一个完整的详情页
        # https://ssr1.scrape.center/detail/1
        logging.info('get detail url %s', detail_url)
        yield detail_url

其中使用了非贪婪通用匹配,使用F12调到开发者工具,对于一个详情页所在的超链接存在于href之后,因此需要使用一个括号表示需要匹配得到的属性,因此这个正则表达式表示的就是匹配超链接,然后使用findall获取所有匹配的内容,最后拼接成一个完整的详情页,因此我们就得到了所需要的详情页的url

接下来,就是爬取详情页。

通过分析可以得到,每个页面所拥有的信息有电影名称,评分,类型,内容简介,封面(只是一个网址)和上映时间,因此需要先获取html代码,再使用正则表达式匹配每一个信息即可。

# 爬取详情页的数据
def scrape_detail(url):
    return scrape_page(url)

def parse_detail(html):
    # 匹配cover信息,可以使用compile将正则表达式转换为一个正则表达式对象
    # 可以每一次不用重新书写正则表达式
    # 封面信息
    cover_pattern = re.compile('class="item.*?<img.*?src="(.*?)".*?class="cover">',re.S)

    # 名称信息
    name_pattern = re.compile('<h2.*?>(.*?)</h2>')

    # 类别信息
    categories_pattern = re.compile('<button.*?category.*?<span>(.*?)</span>.*?</button>',re.S)

    # 上映时间信息
    published_at_pattern = re.compile('(\d{4}-\d{2}-\d{2})\s?上映')

    # 某一部电影的内容信息
    drama_pattern = re.compile('<div.*?drama.*?>.*?<p.*?>(.*?)</p>',re.S)

    # 评分信息
    score_pattern = re.compile('<p.*?score.*?>(.*?)</p>',re.S)

    # 再对每一个信息进行匹配
    # 如果不是特殊的情况基本都使用search
    # 使用strip函数获得给定需求
    cover = re.search(cover_pattern, html).group(1).strip() if re.search(cover_pattern, html) else None

    name = re.search(name_pattern, html).group(1).strip() if re.search(name_pattern, html) else None

    # 因为结果可能有多个所以需要使用findall函数返回一个列表
    categories = re.findall(categories_pattern, html) if re.findall(categories_pattern, html) else []

    published_at = re.search(published_at_pattern, html).group(1) if re.search(published_at_pattern, html) else None

    drama = re.search(drama_pattern, html).group(1).strip() if re.search(drama_pattern, html) else None

    # 注意score是一个浮点数需要强制转换
    score = float(re.search(score_pattern, html).group(1).strip()) if re.search(score_pattern, html) else None

    return {
        '封面': cover,
        '名字': name,
        '类别': categories,
        '上映时间': published_at,
        '内容简介': drama,
        '评分': score
    }

这一部分注释写的很详细,不再赘述。

最后,当然是储存数据

我还没有学如何转换到数据库中,那就姑且用json文件保存就行,然后使用万能的记事本打开即可。

import json
from os import makedirs
from os.path import exists
RESULTS_DIR = 'results'
# 判断是否存在路径如果存在不用管了 , 如果不存在重新创建一个
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)

import multiprocessing


# ensure_ascii = False 可以保证中文字符在文件中正常输出
# indent 两行缩进
def save_data(data):
    name = data.get('名字')
    data_path = f'{RESULTS_DIR}/{name}.json'
    json.dump(data, open(data_path, 'w', encoding='utf-8'),ensure_ascii=False, indent=2)

然后就是主函数

有两种表达方法,第一种就是毫无优化的爬取,也就是一个一个网页进行爬取,最终得到每个电影的信息,第二种就是优化版本,用多进程加速,将每个页码放入进程池中,让电脑的cpu进行加速,就比如说,4核电脑,python默认有4个进程同时进行,实现加速

第一种

def main():
    for page in range(1 , TOTAL_PAGE + 1):
        index_html = scrape_index(page) # 得到列表页的url
        detail_urls = parse_index(index_html) # 得到详情页的url

        # 遍历整个详情页的url 然后提取每一个url的信息 最后输出即可
        for detail_url in detail_urls:
            detail_html = scrape_detail(detail_url)
            data = parse_detail(detail_html)
            logging.info('get detail data %s', data)
            logging.info('saving data to json file')
            save_data(data)
            logging.info('data saved successfully')

        # logging.info('detail urls %s', list(detail_urls))


if __name__ == '__main__':
    main()

第二种

def main(page):
    index_html = scrape_index(page)
    detail_urls = parse_index(index_html)
    for detail_url in detail_urls:
        detail_html = scrape_detail(detail_url)
        data = parse_detail(detail_html)
        logging.info('get detail data %s', data)
        logging.info('saving data to json file')
        save_data(data)
        logging.info('data saved successfully')


if __name__ == '__main__':
    pool = multiprocessing.Pool()
    pages = range(1, TOTAL_PAGE + 1)
    pool.map(main, pages)
    pool.close()

以上就是第一个爬虫程序

如果代码有问题,可以提出来一起学习。

以下是运行结果

  • 作者:xp_xht123
  • 原文链接:https://blog.csdn.net/xp_xht123/article/details/126732271
    更新时间:2022-10-20 12:08:12