Python 多进程网页爬虫代码解析
该代码使用 Python 多进程实现了一个简单的网页爬虫,其编程逻辑如下:/n/n1. 导入所需模块和库,包括 json、os、datetime、requests、logging、re、urllib.parse、multiprocessing 等。/n2. 配置日志的格式和级别。/n3. 设置基础 URL 和总页数,并创建结果目录。/n4. 定义 scrape_page(url) 函数,使用 requests 库发送 HTTP 请求并获取页面内容。/n5. 定义 scrape_index(page) 函数,构造索引页面的 URL,并调用 scrape_page 函数获取页面内容。/n6. 定义 parse_index(html) 函数,使用正则表达式从页面中提取详情页的 URL,并使用 urljoin 函数拼接完整的 URL。/n7. 定义 scrape_detail(url) 函数,构造详情页面的 URL,并调用 scrape_page 函数获取页面内容。/n8. 定义 parse_detail(html) 函数,使用正则表达式从页面中提取封面、名称、分类、上映日期、剧情和评分等信息,并返回字典形式的数据。/n9. 定义 save_data(data) 函数,将数据以 JSON 格式保存到文件中。/n10. 定义主函数 main(page),根据传入的页数调用 scrape_index、parse_index、scrape_detail、parse_detail 和 save_data 函数,实现爬取和保存数据的功能。/n11. 在主程序中,获取当前时间作为开始时间,创建一个进程池,根据总页数创建页数列表,并使用 map 函数并发执行主函数,最后关闭进程池并获取结束时间。/n12. 打印程序运行时间。/n/n该代码通过多进程的方式爬取指定页数的索引页面,然后解析索引页面获取详情页的 URL,进而爬取详情页面并解析页面内容,最后将解析得到的数据保存到 JSON 文件中。/n/n代码示例:/n/npython/nimport json,os,datetime/nfrom os import makedirs/nfrom os.path import exists/nimport requests/nimport logging/nimport re/nfrom urllib.parse import urljoin/nimport multiprocessing/n/nlogging.basicConfig(level=logging.INFO,/n format='%(asctime)s - %(levelname)s: %(message)s')/n/nBASE_URL = 'https://ssr1.scrape.center'/nTOTAL_PAGE = 10/n/nRESULTS_DIR = 'results'/nexists(RESULTS_DIR) or makedirs(RESULTS_DIR)/n/n/ndef scrape_page(url):/n logging.info('scraping %s...', url)/n try:/n response = requests.get(url)/n if response.status_code == 200:/n return response.text/n logging.error(f'get invalid status code {response.status_code} while scraping {url}')/n except requests.RequestException:/n logging.error(f'error occurred while scraping {url}', exc_info=True)/n/n/ndef scrape_index(page):/n index_url = f'{BASE_URL}/page/{page}'/n return scrape_page(index_url)/n/n/ndef parse_index(html):/n pattern = re.compile('<a.*?href='(.*?)'.*?class='name'>')/n items = re.findall(pattern, html)/n if not items:/n return []/n for item in items:/n detail_url = urljoin(BASE_URL, item)/n logging.info(f'get detail url {detail_url}')/n yield detail_url/n/n/ndef scrape_detail(url):/n return scrape_page(url)/n/n/ndef parse_detail(html):/n cover_pattern = re.compile(/n 'class='item.*?<img.*?src='(.*?)'.*?class='cover'>', re.S)/n name_pattern = re.compile('<h2.*?>(.*?)</h2>')/n categories_pattern = re.compile(/n '<button.*?category.*?<span>(.*?)</span>.*?</button>', re.S)/n published_at_pattern = re.compile('(/d{4}-/d{2}-/d{2})/s?上映')/n drama_pattern = re.compile('<div.*?drama.*?>.*?<p.*?>(.*?)</p>', re.S)/n score_pattern = re.compile('<p.*?score.*?>(.*?)</p>', re.S)/n/n cover = re.search(cover_pattern, html).group(/n 1).strip() if re.search(cover_pattern, html) else None/n name = re.search(name_pattern, html).group(/n 1).strip() if re.search(name_pattern, html) else None/n categories = re.findall(categories_pattern, html) if re.findall(/n categories_pattern, html) else []/n published_at = re.search(published_at_pattern, html).group(/n 1) if re.search(published_at_pattern, html) else None/n drama = re.search(drama_pattern, html).group(/n 1).strip() if re.search(drama_pattern, html) else None/n score = float(re.search(score_pattern, html).group(1).strip()/n ) if re.search(score_pattern, html) else None/n/n return {/n 'cover': cover,/n 'name': name,/n 'categories': categories,/n 'published_at': published_at,/n 'drama': drama,/n 'score': score/n }/n/n/ndef save_data(data):/n name = data.get('name')/n data_path = f'{RESULTS_DIR}/{name}.json'/n json.dump(data, open(data_path, 'w', encoding='utf-8'),/n ensure_ascii=False, indent=2)/n/n/ndef main(page):/n logging.info(f'process id is {os.getpid()}, to get page{page}')/n index_html = scrape_index(page)/n detail_urls = parse_index(index_html)/n for detail_url in detail_urls:/n detail_html = scrape_detail(detail_url)/n data = parse_detail(detail_html)/n logging.info(f'get detail data {data}')/n logging.info('saving data to json file')/n save_data(data)/n logging.info('data saved successfully')/n/n/nif __name__ == '__main__':/n start_time = datetime.datetime.now()/n pool = multiprocessing.Pool()/n pages = range(1, TOTAL_PAGE + 1)/n pool.map(main, pages)/n pool.close()/n end_time = datetime.datetime.now()/n print('用时: ',end_time-start_time)/n
原文地址: https://www.cveoy.top/t/topic/o6sv 著作权归作者所有。请勿转载和采集!