算法太难,直接来学爬虫
第一个爬虫程序
爬取这个网站的所有电影名称,评分,类型,内容简介,封面(只是一个网址)和上映时间
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):
#
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()
以上就是第一个爬虫程序
如果代码有问题,可以提出来一起学习。
以下是运行结果