算法太难,直接来学爬虫
第一个爬虫程序
爬取这个网站的所有电影名称,评分,类型,内容简介,封面(只是一个网址)和上映时间
网站在上面
所谓爬虫,就是对于一个网站的爬取,我们先关注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):
- pattern = re.compile('
' ) - 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.*?
' ,re.S) -
- # 名称信息
- name_pattern = re.compile('
(.*?)' ) -
- # 类别信息
- categories_pattern = re.compile('
(.*?) .*?',re.S) -
- # 上映时间信息
- published_at_pattern = re.compile('(\d{4}-\d{2}-\d{2})\s?上映')
-
- # 某一部电影的内容信息
- drama_pattern = re.compile('
.*?(.*?)' ,re.S) -
- # 评分信息
- score_pattern = re.compile('
(.*?)' ,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()
以上就是第一个爬虫程序
如果代码有问题,可以提出来一起学习。
以下是运行结果
