今天就是2024年高考了,再过一个月,新一季大学毕业生也要去社会“接受毒打”。现在大环境找工作也面对僧对粥少,在这个严峻的时代,学会这一招可以让你“快”人一步,打造你的个人简历。我来讲一讲怎么用Python工具来快速产生简历。
好的工作简历除了履历亮眼,一套基本的要求比如说:
针对这三点我们用Python来生成一份简历同时满足这3个要求。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<title>__NAME__的 Resume</title>
<style>
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
</style>
<style>
body{font-family:Georgia;font-size:14px;padding:1em;line-height:1.6}.container,footer,header{max-width:72em;margin:auto}a{color:black;text-decoration:none;border-bottom:1px dashed}p{margin-top:0;margin-bottom:0;line-height:1.6em}header{text-align:center;margin-bottom:1em}#name{font-size:2.6em;font-variant:small-caps}#objective{font-style:italic}@media screen and (min-width: 72em){body{padding:2em 4em;line-height:inherit}#name{float:left;text-align:left}#contact,#objective{text-align:right}}.date{float:right;text-align-last:right}@media screen{.print-only{display:none}}header ul{list-style:none;padding:0;margin:0}header li{display:inline-block;line-height:1.5em}header li::after{content:" |"}header li:last-child::after{content:""}footer{text-align:center}h1,h2,h3,h4{font-weight:normal;margin:0}.container .label{border-bottom:1px solid}section{margin:1.25em 0}section:first-child{margin-top:0.25em}h2{font-style:italic;border-bottom:1px solid grey;margin-bottom:0.5em}.container ul{margin-top:0.1em;margin-bottom:0.1em;padding-left:20px}.entry{margin:0.75em 0}h3{display:inline-block;font-weight:bold}.entry .role{}.entry .role::before{content:"("}.entry .role::after{content:")"}.entry .loc{font-style:italic}.entry .des{font-style:italic}p .entry .des{margin-top:0.1em}.resume-objective{}.resume-project .project-name{font-weight:bold;line-height:1.6em}.resume-project h3{}.meta{}.open-link{padding-right:1.2em;background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CjxwYXRoIGQ9Ik0gNSAzIEMgMy45MDY5MzcyIDMgMyAzLjkwNjkzNzIgMyA1IEwgMyAxOSBDIDMgMjAuMDkzMDYzIDMuOTA2OTM3MiAyMSA1IDIxIEwgMTkgMjEgQyAyMC4wOTMwNjMgMjEgMjEgMjAuMDkzMDYzIDIxIDE5IEwgMjEgMTIgTCAxOSAxMiBMIDE5IDE5IEwgNSAxOSBMIDUgNSBMIDEyIDUgTCAxMiAzIEwgNSAzIHogTSAxNCAzIEwgMTQgNSBMIDE3LjU4NTkzOCA1IEwgOC4yOTI5Njg4IDE0LjI5Mjk2OSBMIDkuNzA3MDMxMiAxNS43MDcwMzEgTCAxOSA2LjQxNDA2MjUgTCAxOSAxMCBMIDIxIDEwIEwgMjEgMyBMIDE0IDMgeiI+PC9wYXRoPgo8L3N2Zz4=');background-repeat:no-repeat;background-size:1em 1em;background-position:right center}.open-link::after{font-size:0.8em}
</style>
<style media="print">
body{padding:0;margin:0;font-size:13px;line-height:inherit}a{text-decoration:none;border-bottom:none}.no-print{display:none}#name{float:left;text-align:left}#contact,#objective{text-align:right}
</style>
</head>
<body>
<header>
__CONTACT_INFO__
</header>
<div class="container">
__SECTIONS__
</div>
</body>
</html>
style的分享按钮如下
关于style的风格,用一个例子解释
#普通文本
class Text:
def __init__(self, text: str) -> None:
self.text = text
def __str__(self) -> str:
return self.text
StrLike = Union[str, Text]
OptionalStrLike = Optional[StrLike]
#带链接的文本,包含带和不带跳转按钮
class LinkText(Text):
def __init__(self, text: str, url: str, show_icon: bool = False) -> None:
super().__init__(text)
self.url = url
self.show_icon = show_icon
def __str__(self) -> str:
if not self.show_icon:
return f'<a target="_blank" href="{self.url}">{self.text}</a>'
else:
return f'<a target="_blank" class="open-link" href="{self.url}">{self.text}</a>'
#分点展示
class BulletedList(Text):
def __init__(self, items: List[StrLike]) -> None:
self.items = items
def __str__(self) -> str:
s = "<ul>\n"
for item in self.items:
s += f"<li><p>{item}</p></li>\n"
s += "</ul>\n"
return s
#斜体
class ItalicsText(Text):
def __init__(self, text: str) -> None:
super().__init__(text)
def __str__(self) -> str:
return f'<p class="des">{self.text}</p>'
#带斜体
class UnderlinedText(Text):
def __init__(self, text: str) -> None:
super().__init__(text)
def __str__(self) -> str:
return f'<span class="label">{self.text}</span>'
#粗黑体
class BoldText(Text):
def __init__(self, text: str) -> None:
super().__init__(text)
def __str__(self) -> str:
return f'<strong>{self.text}</strong>'
#拼接文字
class ConcatText(Text):
def __init__(self, *args: StrLike) -> None:
self.args = args
def __str__(self) -> str:
return "".join(map(str, self.args))
简历段落如下
# 描述每个事项的必须要素:时间、地点、事情的简介、详细描述
class SectionEntry:
def __init__(
self,
title: OptionalStrLike = None,
caption: OptionalStrLike = None,
location: OptionalStrLike = None,
dates: OptionalStrLike = None,
description: OptionalStrLike = None,
) -> None:
self.title = title
self.caption = caption
self.location = location
self.dates = dates
self.description = description
# 经历包括做了哪些事项
class Section:
def __init__(self, title: StrLike, entries: List[SectionEntry]) -> None:
self.title = title
self.entries = entries
# 名字和一些名片要素
class ContactInfo:
def __init__(
self,
name: StrLike,
details: Optional[List[StrLike]] = None,
tag_line: OptionalStrLike = None,
) -> None:
self.name = name
self.details = details
self.tag_line = tag_line
class Resume:
def __init__(self, contact_info: ContactInfo, sections: List[Section]) -> None:
self.contact_info = contact_info
self.sections = sections
self.TEMPLATE = dedent("""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<title>__NAME__’s Resume</title>
<style>
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
</style>
<style>
body{font-family:Georgia;font-size:14px;padding:1em;line-height:1.6}.container,footer,header{max-width:72em;margin:auto}a{color:black;text-decoration:none;border-bottom:1px dashed}p{margin-top:0;margin-bottom:0;line-height:1.6em}header{text-align:center;margin-bottom:1em}#name{font-size:2.6em;font-variant:small-caps}#objective{font-style:italic}@media screen and (min-width: 72em){body{padding:2em 4em;line-height:inherit}#name{float:left;text-align:left}#contact,#objective{text-align:right}}.date{float:right;text-align-last:right}@media screen{.print-only{display:none}}header ul{list-style:none;padding:0;margin:0}header li{display:inline-block;line-height:1.5em}header li::after{content:" |"}header li:last-child::after{content:""}footer{text-align:center}h1,h2,h3,h4{font-weight:normal;margin:0}.container .label{border-bottom:1px solid}section{margin:1.25em 0}section:first-child{margin-top:0.25em}h2{font-style:italic;border-bottom:1px solid grey;margin-bottom:0.5em}.container ul{margin-top:0.1em;margin-bottom:0.1em;padding-left:20px}.entry{margin:0.75em 0}h3{display:inline-block;font-weight:bold}.entry .role{}.entry .role::before{content:"("}.entry .role::after{content:")"}.entry .loc{font-style:italic}.entry .des{font-style:italic}p .entry .des{margin-top:0.1em}.resume-objective{}.resume-project .project-name{font-weight:bold;line-height:1.6em}.resume-project h3{}.meta{}.open-link{padding-right:1.2em;background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CjxwYXRoIGQ9Ik0gNSAzIEMgMy45MDY5MzcyIDMgMyAzLjkwNjkzNzIgMyA1IEwgMyAxOSBDIDMgMjAuMDkzMDYzIDMuOTA2OTM3MiAyMSA1IDIxIEwgMTkgMjEgQyAyMC4wOTMwNjMgMjEgMjEgMjAuMDkzMDYzIDIxIDE5IEwgMjEgMTIgTCAxOSAxMiBMIDE5IDE5IEwgNSAxOSBMIDUgNSBMIDEyIDUgTCAxMiAzIEwgNSAzIHogTSAxNCAzIEwgMTQgNSBMIDE3LjU4NTkzOCA1IEwgOC4yOTI5Njg4IDE0LjI5Mjk2OSBMIDkuNzA3MDMxMiAxNS43MDcwMzEgTCAxOSA2LjQxNDA2MjUgTCAxOSAxMCBMIDIxIDEwIEwgMjEgMyBMIDE0IDMgeiI+PC9wYXRoPgo8L3N2Zz4=');background-repeat:no-repeat;background-size:1em 1em;background-position:right center}.open-link::after{font-size:0.8em}
</style>
<style media="print">
body{padding:0;margin:0;font-size:13px;line-height:inherit}a{text-decoration:none;border-bottom:none}.no-print{display:none}#name{float:left;text-align:left}#contact,#objective{text-align:right}
</style>
</head>
<body>
<header>
__CONTACT_INFO__
</header>
<div class="container">
__SECTIONS__
</div>
</body>
</html>
"""
)
def render_contact_info(self) -> str: # 拼接联系人信息
contact_info = f'<h1 id="name">{self.contact_info.name}</h1>\n'
if self.contact_info.details:
contact_info += '<ul id="contact">\n'
for detail in self.contact_info.details:
contact_info += f"<li>{detail}</li>\n"
contact_info += "</ul>\n"
if self.contact_info.tag_line:
contact_info += f'<p id="objective">{self.contact_info.tag_line}</p>\n'
return contact_info
def render_section(self, section: Section) -> str: # 拼接经历部分
section_html = "<div class='container'>\n"
section_html += "<section>\n"
if section.title:
section_html += f"<h2>{section.title}</h2>\n"
for entry in section.entries:
section_html += f'<div class="entry">\n'
if entry.title:
section_html += f"<h3>{entry.title}</h3>\n"
if entry.caption:
section_html += f'<span class="role">{entry.caption}</span>\n'
if entry.location:
section_html += f'<span class="loc">{entry.location}</span>\n'
if entry.dates:
section_html += f'<span class="date">{entry.dates}</span>\n'
if entry.description:
section_html += f"<p>\n{entry.description}</p>\n"
section_html += "</div>\n"
section_html += "</section>\n"
section_html += "</div>\n"
return section_html
def render_sections(self) -> str: # 把各项经历拼出来
sections_html = ""
for section in self.sections:
sections_html += self.render_section(section)
return sections_html
def render(self) -> str: # 把内容填充到模版里面。替换__NAME__, __CONTACT_INFO__, __SECTIONS__
s = self.TEMPLATE.replace("__NAME__", str(self.contact_info.name))
s = s.replace("__CONTACT_INFO__", self.render_contact_info())
s = s.replace("__SECTIONS__", self.render_sections())
return s
def save(self, filename: str) -> None: # 写到磁盘
with open(filename, "w") as f:
f.write(self.render())
def cli_main(self): # api接口,提供给python调用
parser = argparse.ArgumentParser(description="ResumeBuilder")
parser.add_argument(
"-o",
"--output",
type=str,
dest="output_file",
required=True,
help="Output HTML file name.",
)
args = parser.parse_args()
self.save(args.output_file)
我们来从维基百科获取nvidia华人ceo黄仁勋来制作他的简历吧。
简历内容部分摘取自 https://en.wikipedia.org/wiki/Jensen_Huang
代码可以从这里获取
https://github.com/lumanyu/resume-builder/blob/main/resume1.py
然后执行程序
python resume.py --output resume.html
然后打开resume.html来看下效果吧
当然你可以生产pdf版本的个人简历。这样操作
在网页浏览器打开html,打印成PDF. 在浏览器可以放大缩小PDF在一个页面里。
本文介绍了用python如何快速生成简历,python可以实现规范化整洁的个人简历,同时提供了pdf和html版本。
接着你可以把html的简历放在你个人博客网站下。当然腾讯云产品最近也将推出618特别优惠,优惠分享让更多代码开发爱好者享受福利。活动入口:https://mc.tencent.com/dZlrLoom。看到这里也助你毕业季马到成功,收到心仪的工作offer。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。